From 05711c2f59f4ce6b734ba4c73d1a9d6fd924943a Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Mar 2022 09:50:11 +0545 Subject: [PATCH 001/112] added more methods to CPS_treasury --- .../iconloop/score/example/CPSTreasury.class | Bin 4074 -> 10601 bytes .../score/example/db/ProposalData.class | Bin 3231 -> 3448 bytes .../com/iconloop/score/example/test.class | Bin 1306 -> 794 bytes .../iconloop/score/example/utils/consts.class | Bin 5142 -> 5353 bytes .../libs/CPSTreasury-0.9.1-optimized.jar | Bin 1995 -> 2103 bytes CPSTreasury/build/libs/CPSTreasury-0.9.1.jar | Bin 141681 -> 143220 bytes .../iconloop/score/example/CPSTreasury.java | 132 +++++++++++++++++- .../score/example/db/ProposalData.java | 4 + .../java/com/iconloop/score/example/test.java | 14 +- .../iconloop/score/example/utils/consts.java | 3 + 10 files changed, 141 insertions(+), 12 deletions(-) diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class index d364c8235824dc9e08bed2ebc0902fa2ca061d0d..6246162b74ff9f448c8408a5f2f7c85addb8a02c 100644 GIT binary patch literal 10601 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 delta 437 zcmXw$%}!HM6otRjUV3)hqY|P6Nz@P%EuGXEi7-G#t0*c~0YR;&-cnj?Z@u?Y{71x} z2RLzTOnd>uOpOn~Q}6_g9U1Q(IN58jy?545*7`I0<>=<_-ygq$2|g7#%}kzCTr6^l zs^+rhiZGj}#ML4m*Mzy0TrY5go5FlbZV9y%Zx+-eMV^AezD1Fet83MG?Eg~tLVHY-As}b}JPn29 z3!1LdlTTsM0#YHWC1`ovPlTvcA!dl-!xVlcUZ4E2gjUH<@m1f@3sd~BqG|l(B+v!J vGG$3xM7&WiGyUr$E)xikFw2~GM=;AgNwF_TLl-HoaYs7-|`jM_MQM*v&3_4#WKonvp5fG=#f07!fzVL5HK!p_E)<3HM()ym z;Ct-Y7m|}s&Mo@V_sS(l+A3l%^H|$CkdC4k&&y!nW0kRR=*VK=dIetx1C1+TU|kWA zfh>`Pu@Ryyx=NR%nr}>vWTFvGobY|Rij~f!xBYjbxa~TJ=?^Am@JPq3iN|=NG z9E74-gG$DWw2u5h=J`Ina-gBLx&YU+*SWfY3zQ;HnX15--5T_wO3HByt=5Ijov5zX z9<#RQ)O{&_;aPO5DgUuNR`Xr>T*Bl<^wa8Ed*2kfvLx-E8t`Eb#S#9gdi~a5Ezq;a z)LR4f6e~i_L+~nH4J`ye-_FSp=*3ljT9F|?0ixS3}>bSBWk z|7JA-t!Sf_#5J@d5*B~q9jEV6sxCWRL1g6Mnqo0wiz{o^9 zqN(}{%nGh#VvKdf7(8z}KyaX*pe7O_-$u4-LN}UWk;*tJ%#eg4HCt_r4qT@dK?a@Z wBGCjUa053vWjp#=*~OT}x*jSJB|;Ku`eNu~Rh0R+n8oQe0)gfL&pO=x1-lM8Y5)KL diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/utils/consts.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/utils/consts.class index 08e19bf14acf4bf484b167f2783e7c4d860f2ca9..f9e9dbb01144a46dac7f4ed86cadac2ef49b1c83 100644 GIT binary patch delta 1747 zcmZuyNpl-T6n@XKq_!epa?qwLjol15O%`8?*zV{(MYO*4m0z<_xkmF-}}0C|LzOZ2Txsm z^f4kjz&G?$kxu9EZGPo`IzzAY(Ez>Lf_4oX=rseKHIH)zdc8nz96xxn`6kogf~OsK zHu6>Ac($Oom_~FU-O$mF=eFUu5ot^BP~Eko(DDK$=pCl5TKbXp=9Qa)?=p@1f#-Xn ztcFo{_gxt3d5)ae~FFKa1~(nS4>Po??2skG+RT~zb~Q$gCcDM-+dOd`u6 z=qIFrl@=Q)-wQNien$VUS~Pogdj$Q0$^af#mX7qYk6HYRv9%FLR{{No)|!_rjdbe! z9Ro^RL*WWr{n75#0EU@AnT7&oworD|iuwy!N>c~>8#||QNt9W7u^rY_ZSWruubr9- zwXFGqDeV{vR6&%n!VHS^QZy&SIl(TZn8NFso2V0 zPGrerAlFx}tm@^cr7RwY%D}6xhk_@VdU0f=;1W~LN~Fiz0Gb&JE`v4m6$MI$9_X1g zs!XI0?{*|g>l3`gIA%gUDjkGXjF2r$`Dkn^p3dJ|+KG!L^gTE9x(0Yz{6M~3x*V=W zN6*=TTx=J4MZB4>Y`YTE2viL@&2^SFaMitqDZV=1StvEH!6dS@fm)P-jcJ(k!`Gsp zZ|A7k2MiaqEtzNK*A#5444fv+p_ zUcSCagEUm+eZ2ofLEMvbOO0cVm7~$>`UYM{*N&_=qB~YrZ^NFcqp`YnWaEF_qunc3 z){fn^-awN%1_M`2@_2;Nk~x z2wg?NiC;h!R1Q!aD8f!4K-eKHNm#?a?*u+|yX{nbXiJ|yJ-zq6Pdb0#zH1MixbXNB zM0Ak%Pf&|a)G_wI&IG+gFOSnCog6^>r#M$dM%oJcglT3} z%9`5B;>bEdpF$zvD@IwHjo{C4P)Sz?yFX`|U+#q~%4ISIzV7uX1AK84vUG{_LKF-^ zUouV0z(wmws8UbRd7xE$M(9`hsoG-yYoBR1>1ky24O3Hwp-)KAw@jjnA?Q1Vz^qKx zs5CJSobOS;RvZ4Ti&q5wfXo0MQGv_cR*GKyh_(%p$i;wuLTUX=wq~we`xy-?OGDxc zNBuIa)dOCcUzyrQ`6E=A4OqVcD`gsCzvJYRSFrrnKZdlv8iId9co%h*b+VfZ`m3xM z4pb%^s`57^a+}$zw5x*t!Hy_BYzNbSnI=kUd^-hQKn;U=$^WkmS*Q~BjKs|dv|s`} zOuEvRxe6XfdQEW6ds&$Pj+84Z3zBXcD^xCcTmI14p3WHDge;5OHZla)^D|?eP6LaT ziNYg2>$(UdxS3DamssT2*LNQrANlMOQF&stG)S}3j3@JceOJE)tAt8#6}IFlh?^=c zW4DzJoW*Up47$3W6}+8k3|B@9o@S~Ch4pv`K;J{bGf>TsGNYtTAkVCKWnq1+&LL2l zpWu1Fux#Coj6hrPMh*g%qOhI$fyS*19Xu>HO|(r$4dh+Tg z{A6Qs=OVgcR2MP*b5<3wbZ>Ks_vU+>3;QlZC#tYUZAcTM8~*1mbblX|_|a;FrM+R$xg`Q)?WdP*dByX9cYnu9mgSBxf&YgC!fY zMp53V++PL8J^(3Q@a9dHB)NI)$I2h^C`QG7W~ABKp-?N*=v9F4BPTiy$kWKJZZ+Di zdzoHG_32CEZHPM51oBCqASenrVg)}qA`Hlx^L732Kf%`zxF={CgA{@I1NB{i$HnR| z1v~&yO9u$ETf`{L0002!0RRAy8k3j-7JmtM6IB$)?`uPomZ8f4vI(Ywl9WP~MJlZ* zO{t<43c(5jj+2>}WXfbF%uLz_7u@%K-}ik53sOBtKY$;~<9{-f@KRC`)052m-Q_L! z-Fv5h|MSORM6{iLXT)|zi81P&P$$(sQ?+t^`!W+;^P|>03xC+- zE012VPJ51FqQK1IQ>vqf7T3bU#9kUK6&PFx zg92g~8q_%_ptGP8z0^Xm!wt~cj262^+j4D3$=EnxRk;buBBM4%E4qq{L-QEj2-yiZ zK$ca!@FJ?ptx!6+f{cpW)3~nawrQ$PjJ8AJLQ!2t)pduvxSJhNc$iMJEq`2frsRpr zTc9j4YQeU>68JXoB%@ZNn01xB>gHpVf@q3Sdv)UA;4vD3d>ZKzgdgD@}j9k4x3aK;nA98TX`O1Ed&Ji`5^nWfIEQ{(~Qy=OuctNg&R(byiCD}4) zScbQg(fY(CLla7p3*?Y?TGJ59g1tJ6}K(39MAB$%Pl>gDaTV|Bk`(LJRQ^$%4Jb- z#uRFUPoro0wczkc?x13pHaMAof+?DAqe()ROCxAj2e?;qERGynmzWc>#&K97dL=^J zUe|MyF?twhGws~&Nq=+@M#;pH(Ybwnpn=HW)hT+^-_>JiVPjzz_SZRxbaAuXar_O& z=g}mvc({Ql5&Wvvuu!vTv5mxn=QFiV|fIssOwVDa6lnLVdi$r=bIwKJe zMl*0gdEo_Pd4J=oSweNUrj4A1_l<*bBxUP(w59Emqwx{L!iUOS0c1Fp~Wa zf#*tU#goxFjGJg7SQ5A$+#zrmSQdB*c&Wh4z{>?*iN93>uLiFXI1cU>crAFHz}JJ< z3!DV^2;2+aC~zP627xz&w+Orqe3QWa;F|>=01pbh6MuZGz`MXh0uO_C3w%5H4uS6k z-zD(f;JpHmf%glX2BWaRzg2h~jDo1~VK8#G#z(=&1il}Ptg5jJ&It2qV0{krI&Q@{ zOF8_Whh!CG&3Jb7oTrJN4d=-0={-l*8S+1jY$}F^U3fA)7xbJZ^K_^_(NJww)ehxD zwH&HjWPfj#PF81skRA&48G7)T z6SWguY>bpd1vYbC;D~1n9R=JNcS@r3pz@b^D|{6$22 z=x0XkK%5w()@f~4>$fyJ+kZ4Y&2>LcwUCaCrzTvkc?EZVM__*ed;BV67p+siYuedC zDAM@V8P%AEM2(mmj9S#Z>*O6zvpjW%&wCOzLBScVtB|Xf>G`T@8+=ZpR#;>ht;rN@ zLv^|CxQMqF!Yrc>)AoGLvU1$^)e3_vVK9Zbs_(!+743AVVEYnv!op;;O+t6(;LF;IVK=JIozYeW`T!(s+&sgf!**a8C!rxY1fI9~%@4m#0G%Y`dUKxZ>r z>*XEWb6hp;V1p%P50nn0Mpe&ys)tQ;iFQDihXZ68)sN~_QeF?`S(G5Hp-wtCRKu|> z&6Q|36fP8{G@4r?${`5y5Nh-eNg(0>al-pzW}}oTwv5-<};o;rFl~l z-2%}pqvlfJaN`nkQ z`;kU>a(RpUf#@jin1)-}G*;Yc|D@)Q4&wrLi9EFYitZl_9C1rqBEti&tIZc(w^mA4 zbjI~=j!b_?P2Dg04pa!LxC)ZPw$HQNjiRAJ_Wn2LoaRsU51ZLafAmpn%aiLA207doBJi; zMj4svDc(ReG$oT1&d{GRTgzep?TKWyx2WEm&!vAI^q_nQkHm5A7hId;xVI&ithM?A zIz_KUWZUccZc-w&R8tsZ1Z~3S@KB;>B+JPjoJBJ;N+wQ?EqzP}tB8U<7HGDSd_r?{ zj7JY*ka_~8^D^9ZgEennL6g9GqBWsG+DlfWLi^ygt0opaA1WV_&e4TNdG8@E+502d z=#YPIMFnkLdUkPo90oQ&SG*RCcCKFW5lce_k`-Mn)06a6a3oL5bc~J%#eNo#9%4qV z$!PcGL@l+rOwZE`LEIN*nxMOaxGytmTh^IzdKHfi(uKXjXxHUri{1p8UZ*#LWN*rJ zH{BB?dm9z1)>LtNSEiGp&HMPHhs>qE#mj$kIl0R(fJ`6KM?v{~eCdgHCP{YlL#pwk*sX4b~j?_wSsaSRNNDW~A-{E%sJ z>Vj7c|5I!sCFobol%QKNuBQf!jK0UbhSq>(ft$fC0=Iz`f!o1X2;2c)C-8dwY!H8V zBY2a*o55WIZv}4?_*(FGfs^2FfqTJy0{4Tj6L=?hm%szy8wB19zER*o@Q}d!!8Z$h z06Z-4DEOejw}NjI_;&Ce0^bQfBJemEjRgLo$SE)ypv;qC+|e?h0G|~26d1Rt%=dy- zA>MspZ3(9kwL|$x-G|Fqhq0@*=1+>9s8!t5iC9nSNGmI1Z)#txuQRqtbEU-dG2)Ty860WwIi{>po>-)37U(&pIheh)K(9S0ZOUtl z^wt8sqqHmU6=xqP9l`9A1^P_cseDoN_)6)IX5T0S(d@g@Dt{_gvhH6{O9u$cxLe&Q z1pojxlT8O=35r^~D!~8%0NInc2Rj?fxLe&Q1pojx3;+NJ00{s900000000000DhAW M2qOmM1^@s60CF=1Gynhq diff --git a/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar b/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar index 30a3cedd444506738e78f7bb3a7d40b913419444..48180aabfeda59fd08a1655d2dd6397e5b77629e 100644 GIT binary patch delta 5135 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 K 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 diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java index 8e19beb6..48d9cffe 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java @@ -16,13 +16,14 @@ package com.iconloop.score.example; +import com.iconloop.score.example.db.ProposalData; import score.*; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; -import scorex.util.ArrayList; import score.annotation.EventLog; import score.annotation.External; import score.annotation.Payable; +import scorex.util.ArrayList; import java.math.BigInteger; import java.util.List; @@ -33,6 +34,8 @@ public class CPSTreasury { private final String name; private final String symbol; + private static final String TAG = "CPS_Treasury"; +// private static final byte[] PROPOSAL_DB_PREFIX = "proposal".getBytes(); private static final String ID = "id"; private static final String PROPOSALS_KEYS = "_proposals_keys"; @@ -88,7 +91,134 @@ public String symbol(){ return this.symbol; } + @Payable + public void fallback(){ + Context.revert(TAG + ": ICX can only be send by CPF Treasury Score"); + } + + private void set_id(String _val){ + id.set(_val); + } + + private String get_id(){ + return id.get(); + } + +// private byte proposal_prefix(String _proposal_key){ +// return "m".getBytes(); +// } + + private Boolean _proposal_exists(String _ipfs_key){ + return proposalsKeyListIndex.getOrDefault(_ipfs_key, null) != null; + } + + private void _validate_admins(){ + Context.require((Boolean) Context.call(cpsScore.get(), "is_admin", Context.getCaller()), + TAG + ": Only admins can call this method"); + + } + + private void _validate_owner(){ + Context.require(Context.getCaller().equals(Context.getOwner()), + TAG + ": Only owner can call this method"); + } + + private void _validate_owner_score(Address _score){ + _validate_owner(); + Context.require(_score.isContract(), TAG + "Target " + _score + " is not a score."); + } + + private void _validate_cps_score(){ + Context.require(Context.getCaller().equals(cpsScore.get()), + TAG + ": Only CPS score " + cpsScore.get() + " can send fund using this method."); + } + + private void _validate_cpf_treasury_score(){ + Context.require(Context.getCaller().equals(cpfTreasuryScore.get()), + TAG + ": Only CPF Treasury score " + cpfTreasuryScore.get() + " can send fund using this method."); + } + private void _add_record(ProposalData.ProposalAttributes _proposal){ + ProposalData proposalData = new ProposalData(); + String ipfs_hash = _proposal.ipfs_hash; + Context.require(!_proposal_exists(ipfs_hash), TAG + ": Already have this project"); + proposalsKeys.add(ipfs_hash); + proposalData.addDataToProposalDB(_proposal, ipfs_hash); + proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); + } + + private Map _get_projects(String _proposal_key){ + ProposalData proposalData = new ProposalData(); + return proposalData.getDataFromProposalDB(_proposal_key); + } + + @External + public void set_cps_score(Address _score){ + _validate_owner_score(_score); + cpsScore.set(_score); + } + + @External(readonly = true) + public Address get_cps_score(){ + return cpsScore.get(); + } + + @External + public void set_cpf_treasury_score(Address _score){ + _validate_owner_score(_score); + cpfTreasuryScore.set(_score); + } + + @External(readonly = true) + public Address get_cpf_treasury_score(){ + return cpfTreasuryScore.get(); + } + + @External + public void set_bnUSD_score(Address _score){ + _validate_owner_score(_score); + balancedDollar.set(_score); + } + + @External + public Address get_bnUSD_score(){ + return balancedDollar.get(); + } + + @External(readonly = true) + public void get_contributor_projected_fund(Address _wallet_address){ + ProposalData proposalData = new ProposalData(); + BigInteger totalAmountToBePaidICX = BigInteger.ZERO; + BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; + List> projectDetails = new ArrayList<>(); + for (int i = 0; i < proposalsKeys.size(); i++){ + String _ipfs_key = proposalsKeys.get(i); + if (proposalData.getProposalAttributesDetails(_ipfs_key, consts.STATUS).equals(DISQUALIFIED)){ + if (proposalData.getProposalAttributesDetails(_ipfs_key, consts.CONTRIBUTOR_ADDRESS).equals(_wallet_address.toString())){ + BigInteger totalInstallment = new BigInteger(proposalData.getProposalAttributesDetails(_ipfs_key, consts.PROJECT_DURATION)); + BigInteger totalPaidCount = new BigInteger(proposalData.getProposalAttributesDetails(_ipfs_key, consts.INSTALLMENT_COUNT)); + if (totalPaidCount.compareTo(totalInstallment) < 0){ + String flag = proposalData.getProposalAttributesDetails(_ipfs_key, consts.TOKEN); + BigInteger totalBudget = new BigInteger(proposalData.getProposalAttributesDetails(_ipfs_key, consts.TOTAL_BUDGET)); + BigInteger totalPaidAmount = new BigInteger(proposalData.getProposalAttributesDetails(_ipfs_key, consts.WITHDRAW_AMOUNT)); + Map project_details = Map.of( + consts.IPFS_HASH, _ipfs_key, + consts.TOTAL_BUDGET, totalBudget.toString(), + consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount.toString(), + consts.TOTAL_TIMES_INSTALLMENT_PAID, totalPaidCount.toString(), + consts.INSTALLMENT_AMOUNT, totalBudget.divide(totalInstallment).toString()); + projectDetails.add(project_details); + if (flag.equals(consts.ICX)){ + totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(totalInstallment)); + } + else { + totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget); + } + } + } + } + } + } @EventLog(indexed = 1) public void FundReturned(Address _sponsor_address, String note){} diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java b/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java index 99e3746f..21fec917 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java @@ -56,4 +56,8 @@ public Map getDataFromProposalDB(String prefix){ ); } + public String getProposalAttributesDetails(String prefix, String attribute){ + return proposalsData.at(prefix).getOrDefault(attribute, ""); + } + } diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/test.java b/CPSTreasury/src/main/java/com/iconloop/score/example/test.java index ba03cd17..35c4b1b0 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/test.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/test.java @@ -8,16 +8,8 @@ public class test { public static void main(String[] args) throws Exception { // Create raw data. - String params = "" + "{\"method\":\"_swap_icx\"}"; - byte[] data = params.getBytes(); - - System.out.println(data); - - String unpacked = new String(data); - System.out.println(unpacked); - - JsonObject json = Json.parse(unpacked).asObject(); - String method = json.get("method").asString(); - System.out.println(method); + String prefix = "proposal" + "|" + "10" + "|" + "proposal_key"; + byte[] prefix_byte = prefix.getBytes(); + System.out.println(prefix_byte); } } diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/utils/consts.java b/CPSTreasury/src/main/java/com/iconloop/score/example/utils/consts.java index d5461eb3..d350dd62 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/utils/consts.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/utils/consts.java @@ -127,5 +127,8 @@ public consts(){} public static final String INSTALLMENT_COUNT = "installment_count"; public static final String SPONSOR_REWARD_COUNT = "sponsor_reward_count"; public static final String TOKEN = "token"; + public static final String TOTAL_INSTALLMENT_PAID = "total_installment_paid"; + public static final String TOTAL_TIMES_INSTALLMENT_PAID = "total_times_installment_paid"; + public static final String INSTALLMENT_AMOUNT = "installment_amount"; } From f2a9a3989bc9862e9d006be065f5eb4636643b94 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Mar 2022 11:00:27 +0545 Subject: [PATCH 002/112] added get_contributors_projected_fund and get_sponsor_projected fund --- .../iconloop/score/example/CPSTreasury.java | 95 ++++++++++++++++--- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java index 48d9cffe..88cd9d50 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java @@ -26,6 +26,7 @@ import scorex.util.ArrayList; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; @@ -147,7 +148,7 @@ private void _add_record(ProposalData.ProposalAttributes _proposal){ proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); } - private Map _get_projects(String _proposal_key){ + private Map _get_projects(String _proposal_key){ ProposalData proposalData = new ProposalData(); return proposalData.getDataFromProposalDB(_proposal_key); } @@ -186,38 +187,104 @@ public Address get_bnUSD_score(){ } @External(readonly = true) - public void get_contributor_projected_fund(Address _wallet_address){ + public Map get_contributor_projected_fund(Address _wallet_address){ ProposalData proposalData = new ProposalData(); BigInteger totalAmountToBePaidICX = BigInteger.ZERO; BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; List> projectDetails = new ArrayList<>(); for (int i = 0; i < proposalsKeys.size(); i++){ String _ipfs_key = proposalsKeys.get(i); - if (proposalData.getProposalAttributesDetails(_ipfs_key, consts.STATUS).equals(DISQUALIFIED)){ - if (proposalData.getProposalAttributesDetails(_ipfs_key, consts.CONTRIBUTOR_ADDRESS).equals(_wallet_address.toString())){ - BigInteger totalInstallment = new BigInteger(proposalData.getProposalAttributesDetails(_ipfs_key, consts.PROJECT_DURATION)); - BigInteger totalPaidCount = new BigInteger(proposalData.getProposalAttributesDetails(_ipfs_key, consts.INSTALLMENT_COUNT)); - if (totalPaidCount.compareTo(totalInstallment) < 0){ - String flag = proposalData.getProposalAttributesDetails(_ipfs_key, consts.TOKEN); - BigInteger totalBudget = new BigInteger(proposalData.getProposalAttributesDetails(_ipfs_key, consts.TOTAL_BUDGET)); - BigInteger totalPaidAmount = new BigInteger(proposalData.getProposalAttributesDetails(_ipfs_key, consts.WITHDRAW_AMOUNT)); + Map proposal_details = proposalData.getDataFromProposalDB(_ipfs_key); + if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)){ + if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())){ + int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); + int totalPaidCount = (int) proposal_details.get(consts.INSTALLMENT_COUNT); + if (totalPaidCount < totalInstallment){ + String flag = (String) proposal_details.get(consts.TOKEN); + BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); + BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); + Map project_details = Map.of( consts.IPFS_HASH, _ipfs_key, + consts.TOKEN, flag, consts.TOTAL_BUDGET, totalBudget.toString(), consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount.toString(), - consts.TOTAL_TIMES_INSTALLMENT_PAID, totalPaidCount.toString(), - consts.INSTALLMENT_AMOUNT, totalBudget.divide(totalInstallment).toString()); + consts.TOTAL_INSTALLMENT_COUNT, String.valueOf(totalInstallment), + consts.TOTAL_TIMES_INSTALLMENT_PAID, String.valueOf(totalPaidCount), + consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)).toString()); + + projectDetails.add(project_details); + if (flag.equals(consts.ICX)){ + totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); + } + else { + totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); + } + } + } + } + } + return Map.of( + "data", projectDetails, + "project_count", projectDetails.size(), + "total_amount", Map.of("ICX", totalAmountToBePaidICX, "bnUSD", totalAmountToBePaidbnUSD), + "withdraw_amount_icx", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.ICX, BigInteger.ZERO), + "withdraw_amount_bnUSD", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.bnUSD, BigInteger.ZERO)); + } + + + @External(readonly = true) + public Map get_sponsor_projected_fund(Address _wallet_address){ + ProposalData proposalData = new ProposalData(); + BigInteger totalAmountToBePaidICX = BigInteger.ZERO; + BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; + BigInteger totalSponsorBondICX = BigInteger.ZERO; + BigInteger totalSponsorBondbnUSD = BigInteger.ZERO; + List> projectDetails = new ArrayList<>(); + for (int i = 0; i < proposalsKeys.size(); i++){ + String _ipfs_key = proposalsKeys.get(i); + Map proposal_details = proposalData.getDataFromProposalDB(_ipfs_key); + if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)){ + if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())){ + int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); + int totalPaidCount = (int) proposal_details.get(consts.INSTALLMENT_COUNT); + if (totalPaidCount < totalInstallment){ + String flag = (String) proposal_details.get(consts.TOKEN); + BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); + BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); + BigInteger depositedSponsorBond = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); + + Map project_details = Map.of( + consts.IPFS_HASH, _ipfs_key, + consts.TOKEN, flag, + consts.TOTAL_BUDGET, totalBudget.toString(), + consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount.toString(), + consts.TOTAL_INSTALLMENT_COUNT, String.valueOf(totalInstallment), + consts.TOTAL_TIMES_INSTALLMENT_PAID, String.valueOf(totalPaidCount), + consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)).toString(), + consts.SPONSOR_BOND_AMOUNT, depositedSponsorBond.toString()); + projectDetails.add(project_details); if (flag.equals(consts.ICX)){ - totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(totalInstallment)); + totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); + totalSponsorBondICX = totalSponsorBondICX.add(depositedSponsorBond); } else { - totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget); + totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); + totalSponsorBondbnUSD = totalSponsorBondbnUSD.add(depositedSponsorBond); } } } } } + return Map.of( + "data", projectDetails, + "project_count", projectDetails.size(), + "total_amount", Map.of("ICX", totalAmountToBePaidICX, "bnUSD", totalAmountToBePaidbnUSD), + "withdraw_amount_icx", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.ICX, BigInteger.ZERO), + "withdraw_amount_bnUSD", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.bnUSD, BigInteger.ZERO), + "total_sponsor_bond", Map.of("ICX", totalSponsorBondICX, "bnUSD", totalSponsorBondbnUSD) + ); } @EventLog(indexed = 1) From 24ff56763555ffe644f231a0cd66a5828be94b9c Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Mar 2022 11:01:48 +0545 Subject: [PATCH 003/112] new commits for getting contributors and sponsors projected fund in CPS treasury --- .../iconloop/score/example/CPSTreasury.class | Bin 10601 -> 13182 bytes .../db/ProposalData$ProposalAttributes.class | Bin 695 -> 695 bytes .../score/example/db/ProposalData.class | Bin 3448 -> 4163 bytes .../iconloop/score/example/utils/consts.class | Bin 5353 -> 5487 bytes .../libs/CPSTreasury-0.9.1-optimized.jar | Bin 2103 -> 7656 bytes CPSTreasury/build/libs/CPSTreasury-0.9.1.jar | Bin 143220 -> 145292 bytes .../score/example/db/ProposalData.java | 83 ++++++++++-------- .../iconloop/score/example/utils/consts.java | 3 + 8 files changed, 48 insertions(+), 38 deletions(-) diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class index 6246162b74ff9f448c8408a5f2f7c85addb8a02c..367d79bc14ffae074c3aa31d7cb8bf322b808e6f 100644 GIT binary patch literal 13182 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 diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData.class index 58924fb936e75f2b11e2e2ce32847455b8dbcf6e..8668816696b57da91df832bc072b3d4a65c40bf3 100644 GIT binary patch literal 4163 zcmbtXX?Gh}8Gc4yG_oePe7z6z3=ke ztAG6a{l5UX8-MD+y;z9h9xTSOgj^I?VmO9J<7h=*#06oCLfJxxBVGlkp)E8v;ma~SF2h&E_^VNTEsAgGcv8nxvhp{hcsh z<&5oE>2b#_W|k($M>ND{bBjgOtvHs3lTGU5(^t%^W;$;c7t^!!UtApVEiRhQx4HJC z7Wdw{oO745j=4Nmuq#D|uFv1YLrwB7$10e)A`=o=_J@IKQY3Q4GLw-nSVecD=2eBZ z5=39vPAj*rD}{N>xnR!cDN)mQ#>}%2a>Dz< zR(B~!AH&lbyO7TDta;lmrE7t(R?I>vZ>6*I>7Z&SP1j^rd(3QB$P0F;7}szi`60aQ z31+T0!pO$zl>>Fmv1YuU;YRQOKbK&*N{+RVTakEdXcjiy8OvR=v*%35ELg7PaLGP4 zg&g*jV;6!=Px83ClN%lEuZb#dE}uSQmKdsg{=3yCZJCnZ(T`{Herh{r?TVAJPUR$# z-Qg~{tAla~cJNuN?4GeC-DLxxzQ*S zQ@9+(?^!ioyo1>6Imy0yOhcRh-FJfulsV-ztF!DfAu++nxg`%EVc-vPzC?2_4ZMlB z2(2En&CUDJ*6W!yK^6PhZ?HMXhp7ZhPGD*-8{$;=`U*bou*rgX><7Ud168~&pyz?M z4;KdB!5?}0Iv|O&1 z@I^$zvfN{Ro0$_(`fE+vR0V7}ZAwG*s+q4?GYd3JPSraPE*k>U0+FD0y>5j94Fy2Y ztq-3(Kf}Uk=m1tHp=HLIv=+=to*Ql>tZ6)XV?S}N7Vi@8P1bKdjEwHu z!Oj~k{O1C@%U+O<%*jh+U-FSgK&v%v5cFVaF6x*31TRZ#g-3}Ot>xg+qT$Z^0|gJ0 z^?veRK6Kic^by?3m(;y{DRyFqpcx4N9Izn81g6htkeXwInMHgX?`_++fwgA zd&@iW1&-~WFosW(HfjdAh=<5&_!KTNFr2Kt$Zre3yQ+u`uc0M^zoK>M9ki{XJwkkn z)(drC7^@d{_`-O-&{)MbU*1_S?^;E|mv`68)w;YVlvmN~+xBfD>knnzZm_d~dSS4$ z!Fplc&bDtM-%&5W$=kwuSdX#3fW7GBPl^=n@Dzse8V>M|If%b8FCX9# z{)NL@3`ew`IO?V1mRh*|R50*(7>`JLNPQZYnU2rUe=I^VD3EN;;j^5?Y()~xYJ{Te ziEV$z&6ir#PNr=rNSoTVhFc_ox31#0*-NczH}e;2y=Z#sJ)XKv-Cjj(OLe>2TSYun zw|EKlrtkBnM^&TVQ-x&N=-1#PR7lCx*D7rY_ zg>C#1J4BE=O_<8@x8&0p!5cV^zZ0(hiBXox{aOkqw9^>Vu3%hy1{2!roF^UJPhZS? zST@(aV$r-}Y16zysiB<-9rGbJd?3^KcTMe7tcttdMnvsaEC5nbb-Pc+)LzA`QWjT9 zmGY=gHSAN}>Zm{W4t2nv(W4IeRG&KRQ~m0QPYtMpzP~}0_NndaZr{reX(qn^Io6t~ z2Oa3;e;;=8oJkDe2nHFK?S$bSd=%cqUbq=qd<;cetY8;^ElV3^=pjP6#jil(G0p)L RWycuh5yUv_34Fah_8+P=8R-B3 literal 3448 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 f(3xU$wr~3G1 diff --git a/CPSTreasury/build/libs/CPSTreasury-0.9.1-optimized.jar b/CPSTreasury/build/libs/CPSTreasury-0.9.1-optimized.jar index 5b6383b802c1e6236a394a85611d5393fe404a47..1a858862ad15cf1079c741f1bbb9667fcbc19073 100644 GIT binary patch literal 7656 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 diff --git a/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar b/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar index 48180aabfeda59fd08a1655d2dd6397e5b77629e..c97ff610cd280bfe053d69332c304abff3cd421c 100644 GIT binary patch delta 12502 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 delta 10447 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 proposalsData = Context.newBranchDB("proposals_data", String.class); + private static final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); + private static final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); + private static final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSORS_REWARDS, BigInteger.class); + private static final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); + private static final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); + private static final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); + private static final BranchDB> token = Context.newBranchDB(consts.TOKEN, String.class); + private static final BranchDB> withdrawAmount = Context.newBranchDB(consts.WITHDRAW_AMOUNT, BigInteger.class); + private static final BranchDB> sponsorWithdrawAmount = Context.newBranchDB(consts.SPONSOR_WITHDRAW_AMOUNT, BigInteger.class); + private static final BranchDB> remainingAmount = Context.newBranchDB(consts.REMAINING_AMOUNT, BigInteger.class); + private static final BranchDB> sponsorRemainingAmount = Context.newBranchDB(consts.SPONSOR_REMAINING_AMOUNT, BigInteger.class); + private static final BranchDB> installmentCount = Context.newBranchDB(consts.INSTALLMENT_COUNT, Integer.class); + private static final BranchDB> sponsorRewardCount = Context.newBranchDB(consts.SPONSOR_REWARD_COUNT, Integer.class); + private static final BranchDB> status = Context.newBranchDB(consts.STATUS, String.class); + + + public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ - proposalsData.at(prefix).set(consts.IPFS_HASH, _proposals.ipfs_hash); - proposalsData.at(prefix).set(consts.TOTAL_BUDGET, _proposals.total_budget.toString()); - proposalsData.at(prefix).set(consts.SPONSORS_REWARDS, _proposals.sponsor_reward.toString()); - proposalsData.at(prefix).set(consts.PROJECT_DURATION, String.valueOf(_proposals.project_duration)); - proposalsData.at(prefix).set(consts.SPONSOR_ADDRESS, _proposals.sponsor_address); - proposalsData.at(prefix).set(consts.CONTRIBUTOR_ADDRESS, _proposals.contributor_address); - proposalsData.at(prefix).set(consts.WITHDRAW_AMOUNT, "0"); - proposalsData.at(prefix).set(consts.SPONSOR_WITHDRAW_AMOUNT, "0"); - proposalsData.at(prefix).set(consts.REMAINING_AMOUNT, _proposals.total_budget.toString()); - proposalsData.at(prefix).set(consts.SPONSOR_REMAINING_AMOUNT, _proposals.sponsor_reward.toString()); - proposalsData.at(prefix).set(consts.INSTALLMENT_COUNT, String.valueOf(_proposals.project_duration)); - proposalsData.at(prefix).set(consts.SPONSOR_REWARD_COUNT, String.valueOf(_proposals.project_duration)); - proposalsData.at(prefix).set(consts.TOKEN, _proposals.token); + ipfsHash.at(prefix).set(_proposals.ipfs_hash); + totalBudget.at(prefix).set(_proposals.total_budget); + sponsorReward.at(prefix).set(_proposals.sponsor_reward); + projectDuration.at(prefix).set(_proposals.project_duration); + sponsorAddress.at(prefix).set(Address.fromString(_proposals.sponsor_address)); + contributorAddress.at(prefix).set(Address.fromString(_proposals.contributor_address)); + withdrawAmount.at(prefix).set(BigInteger.ZERO); + sponsorWithdrawAmount.at(prefix).set(BigInteger.ZERO); + remainingAmount.at(prefix).set(_proposals.total_budget); + sponsorRemainingAmount.at(prefix).set(_proposals.sponsor_reward); + installmentCount.at(prefix).set(_proposals.project_duration); + sponsorRewardCount.at(prefix).set(_proposals.project_duration); + status.at(prefix).set(_proposals.token); } - public Map getDataFromProposalDB(String prefix){ + public Map getDataFromProposalDB(String prefix){ return Map.ofEntries( - Map.entry(consts.IPFS_HASH, proposalsData.at(prefix).getOrDefault(consts.IPFS_HASH, "")), - Map.entry(consts.TOTAL_BUDGET, proposalsData.at(prefix).getOrDefault(consts.TOTAL_BUDGET, "")), - Map.entry(consts.SPONSORS_REWARDS, proposalsData.at(prefix).getOrDefault(consts.SPONSORS_REWARDS, "")), - Map.entry(consts.PROJECT_DURATION, proposalsData.at(prefix).getOrDefault(consts.PROJECT_DURATION, "")), - Map.entry(consts.SPONSOR_ADDRESS, proposalsData.at(prefix).getOrDefault(consts.SPONSOR_ADDRESS, "")), - Map.entry(consts.CONTRIBUTOR_ADDRESS, proposalsData.at(prefix).getOrDefault(consts.CONTRIBUTOR_ADDRESS, "")), - Map.entry(consts.WITHDRAW_AMOUNT, proposalsData.at(prefix).getOrDefault(consts.WITHDRAW_AMOUNT, "")), - Map.entry(consts.INSTALLMENT_COUNT, proposalsData.at(prefix).getOrDefault(consts.INSTALLMENT_COUNT, "")), - Map.entry(consts.SPONSOR_REWARD_COUNT, proposalsData.at(prefix).getOrDefault(consts.SPONSOR_REWARD_COUNT, "")), - Map.entry(consts.SPONSOR_WITHDRAW_AMOUNT, proposalsData.at(prefix).getOrDefault(consts.SPONSOR_WITHDRAW_AMOUNT, "")), - Map.entry(consts.REMAINING_AMOUNT, proposalsData.at(prefix).getOrDefault(consts.REMAINING_AMOUNT, "")), - Map.entry(consts.SPONSOR_REMAINING_AMOUNT, proposalsData.at(prefix).getOrDefault(consts.SPONSOR_REMAINING_AMOUNT, "")), - Map.entry(consts.TOKEN, proposalsData.at(prefix).getOrDefault(consts.TOKEN, "")) + Map.entry(consts.IPFS_HASH, ipfsHash.at(prefix).getOrDefault("")), + Map.entry(consts.TOTAL_BUDGET, totalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(consts.SPONSORS_REWARDS, sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(consts.PROJECT_DURATION, projectDuration.at(prefix).getOrDefault(0)), + Map.entry(consts.SPONSOR_ADDRESS, sponsorAddress.at(prefix).get().toString()), + Map.entry(consts.CONTRIBUTOR_ADDRESS, contributorAddress.at(prefix).get().toString()), + Map.entry(consts.WITHDRAW_AMOUNT, withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(consts.INSTALLMENT_COUNT, installmentCount.at(prefix).getOrDefault(0)), + Map.entry(consts.SPONSOR_REWARD_COUNT, sponsorRewardCount.at(prefix).getOrDefault(0)), + Map.entry(consts.SPONSOR_WITHDRAW_AMOUNT, sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(consts.REMAINING_AMOUNT, remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(consts.SPONSOR_REMAINING_AMOUNT, sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(consts.TOKEN, token.at(prefix).getOrDefault("")) ); } - - public String getProposalAttributesDetails(String prefix, String attribute){ - return proposalsData.at(prefix).getOrDefault(attribute, ""); - } - } diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/utils/consts.java b/CPSTreasury/src/main/java/com/iconloop/score/example/utils/consts.java index d350dd62..4f81e989 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/utils/consts.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/utils/consts.java @@ -130,5 +130,8 @@ public consts(){} public static final String TOTAL_INSTALLMENT_PAID = "total_installment_paid"; public static final String TOTAL_TIMES_INSTALLMENT_PAID = "total_times_installment_paid"; public static final String INSTALLMENT_AMOUNT = "installment_amount"; + public static final String TOTAL_INSTALLMENT_COUNT = "total_installment_count"; + public static final String SPONSOR_BOND_AMOUNT = "sponsor_bond_amount"; + } From 0877ffb69792d4b5ff37df7a825b2db0af1641fd Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 21 Mar 2022 12:02:38 +0545 Subject: [PATCH 004/112] changed the private db variables to protected db variables --- .../iconloop/score/example/CPSTreasury.java | 126 +++++++++++++++++- .../score/example/db/ProposalData.java | 32 ++--- .../java/com/iconloop/score/example/test.java | 15 --- 3 files changed, 138 insertions(+), 35 deletions(-) delete mode 100644 CPSTreasury/src/main/java/com/iconloop/score/example/test.java diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java index 88cd9d50..6c719658 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java @@ -32,11 +32,11 @@ import com.iconloop.score.example.utils.consts; -public class CPSTreasury { +public class CPSTreasury extends ProposalData{ private final String name; private final String symbol; private static final String TAG = "CPS_Treasury"; -// private static final byte[] PROPOSAL_DB_PREFIX = "proposal".getBytes(); + private static final String PROPOSAL_DB_PREFIX = "proposal"; private static final String ID = "id"; private static final String PROPOSALS_KEYS = "_proposals_keys"; @@ -105,9 +105,9 @@ private String get_id(){ return id.get(); } -// private byte proposal_prefix(String _proposal_key){ -// return "m".getBytes(); -// } + private String proposal_prefix(String _proposal_key){ + return PROPOSAL_DB_PREFIX + "|" + id.get() + "|" + _proposal_key; + } private Boolean _proposal_exists(String _ipfs_key){ return proposalsKeyListIndex.getOrDefault(_ipfs_key, null) != null; @@ -287,6 +287,116 @@ public Address get_bnUSD_score(){ ); } + private void _deposit_proposal_fund(ProposalData.ProposalAttributes _proposals, BigInteger _value){ + _add_record(_proposals); + ProposalFundDeposited(_proposals.ipfs_hash, "Received " + _proposals.ipfs_hash + " " + _value + " " + + consts.bnUSD + " fund from CPF"); + } + + @External + @Payable + public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, BigInteger _added_sponsor_reward, + int _added_installment_count){ + ProposalData proposalData = new ProposalData(); + Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS hash."); + String proposalPrefix = proposal_prefix(_ipfs_key); + Map proposalDetails = proposalData.getDataFromProposalDB(proposalPrefix); + BigInteger totalBudget = (BigInteger) proposalDetails.get(consts.TOTAL_BUDGET); + BigInteger sponsorReward = (BigInteger) proposalDetails.get(consts.SPONSORS_REWARDS); + int totalDuration = (int) proposalDetails.get(consts.PROJECT_DURATION); + BigInteger remainingAmount = (BigInteger) proposalDetails.get(consts.REMAINING_AMOUNT); + BigInteger sponsorRemainingAmount = (BigInteger) proposalDetails.get(consts.SPONSOR_REMAINING_AMOUNT); + int installmentCount = (int) proposalDetails.get(consts.INSTALLMENT_COUNT); + int sponsorRewardCount = (int) proposalDetails.get(consts.SPONSOR_REWARD_COUNT); + String flag = (String) proposalDetails.get(consts.TOKEN); + + ProposalData.totalBudget.at(proposalPrefix).set(totalBudget.add(_added_budget)); + ProposalData.sponsorReward.at(proposalPrefix).set(sponsorReward.add(_added_sponsor_reward)); + ProposalData.projectDuration.at(proposalPrefix).set(totalDuration + _added_installment_count); + ProposalData.remainingAmount.at(proposalPrefix).set(remainingAmount.add(_added_budget)); + ProposalData.sponsorRemainingAmount.at(proposalPrefix).set(sponsorRemainingAmount.add(_added_sponsor_reward)); + ProposalData.installmentCount.at(proposalPrefix).set(installmentCount + _added_installment_count); + ProposalData.sponsorRewardCount.at(proposalPrefix).set(sponsorRewardCount + _added_installment_count); + + ProposalFundDeposited(_ipfs_key, _ipfs_key + ": Added Budget: " + _added_budget + " " + + flag + "and Added time: " + _added_installment_count + " Successfully"); + } + + @External + public void send_installment_to_contributor(String _ipfs_key){ + _validate_cps_score(); + Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS Hash."); + BigInteger installmentAmount = BigInteger.ZERO; + ProposalData proposalData = new ProposalData(); + String prefix = proposal_prefix(_ipfs_key); + + int installmentCount = ProposalData.installmentCount.at(prefix).getOrDefault(0); + BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); + BigInteger remainingAmount = ProposalData.remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); + Address contributorAddress = ProposalData.contributorAddress.at(prefix).get(); + String flag = ProposalData.token.at(prefix).get(); + + try { + if (installmentCount == 1) { + installmentAmount = remainingAmount; + } else { + installmentAmount = remainingAmount.divide(BigInteger.valueOf(installmentCount)); + } + int newInstallmentCount = installmentCount - 1; + ProposalData.installmentCount.at(prefix).set(newInstallmentCount); + ProposalData.remainingAmount.at(prefix).set(remainingAmount.subtract(installmentAmount)); + ProposalData.withdrawAmount.at(prefix).set(withdrawAmount.add(installmentAmount)); + installmentFundRecord.at(contributorAddress.toString()).set(flag, + installmentFundRecord.at(contributorAddress.toString()).get(flag).add(installmentAmount)); + ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); + + if (newInstallmentCount == 0){ + ProposalData.status.at(prefix).set(COMPLETED); + } + } + catch (Exception e){ + Context.revert(TAG + ": Network problem. Sending project funds to contributor. " + e); + } + } + + @External + public void send_reward_to_sponsor(String _ipfs_key){ + _validate_cps_score(); + + Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS Hash."); + BigInteger installmentAmount = BigInteger.ZERO; + String prefix = proposal_prefix(_ipfs_key); + + int sponsorRewardCount = ProposalData.sponsorRewardCount.at(prefix).getOrDefault(0); + BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); + BigInteger sponsorRemainingAmount = ProposalData.sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); + Address sponsorAddress = ProposalData.sponsorAddress.at(prefix).get(); + String flag = ProposalData.token.at(prefix).get(); + + try { + if (sponsorRewardCount == 1) { + installmentAmount = sponsorRemainingAmount; + } else { + installmentAmount = sponsorRemainingAmount.divide(BigInteger.valueOf(sponsorRewardCount)); + } + int newSponsorRewardCount = sponsorRewardCount - 1; + ProposalData.sponsorRewardCount.at(prefix).set(newSponsorRewardCount); + ProposalData.sponsorWithdrawAmount.at(prefix).set(sponsorWithdrawAmount.add(installmentAmount)); + ProposalData.sponsorRemainingAmount.at(prefix).set(sponsorRemainingAmount.subtract(installmentAmount)); + installmentFundRecord.at(sponsorAddress.toString()).set(flag, installmentFundRecord.at(sponsorAddress.toString()).get(flag).add(installmentAmount)); + ProposalFundSent(sponsorAddress, "New installment " + installmentAmount + " " + + flag + " sent to sponsor address."); + } + catch (Exception e){ + Context.revert(TAG + ": Network problem. Sending project funds to sponsor."); + } + } + + @External + public void disqualify_project(String _ipfs_key){ + + } + @EventLog(indexed = 1) public void FundReturned(Address _sponsor_address, String note){} @@ -299,5 +409,11 @@ public void ProposalDisqualified(String _ipfs_key, String note){} @EventLog(indexed = 1) public void FundReceived(Address _sponsor_address, String note){} + @EventLog(indexed = 1) + public void ProposalFundDeposited(String _ipfs_key, String note){} + + @EventLog(indexed = 1) + public void ProposalFundSent(Address _receiver_address, String note){} + } diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java b/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java index c384edac..12d9f558 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java @@ -15,21 +15,22 @@ public static class ProposalAttributes{ public String token; public String contributor_address; public String sponsor_address; + public String status; } - private static final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); - private static final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); - private static final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSORS_REWARDS, BigInteger.class); - private static final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); - private static final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); - private static final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); - private static final BranchDB> token = Context.newBranchDB(consts.TOKEN, String.class); - private static final BranchDB> withdrawAmount = Context.newBranchDB(consts.WITHDRAW_AMOUNT, BigInteger.class); - private static final BranchDB> sponsorWithdrawAmount = Context.newBranchDB(consts.SPONSOR_WITHDRAW_AMOUNT, BigInteger.class); - private static final BranchDB> remainingAmount = Context.newBranchDB(consts.REMAINING_AMOUNT, BigInteger.class); - private static final BranchDB> sponsorRemainingAmount = Context.newBranchDB(consts.SPONSOR_REMAINING_AMOUNT, BigInteger.class); - private static final BranchDB> installmentCount = Context.newBranchDB(consts.INSTALLMENT_COUNT, Integer.class); - private static final BranchDB> sponsorRewardCount = Context.newBranchDB(consts.SPONSOR_REWARD_COUNT, Integer.class); - private static final BranchDB> status = Context.newBranchDB(consts.STATUS, String.class); + protected static final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); + protected static final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); + protected static final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSORS_REWARDS, BigInteger.class); + protected static final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); + protected static final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); + protected static final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); + protected static final BranchDB> token = Context.newBranchDB(consts.TOKEN, String.class); + protected static final BranchDB> withdrawAmount = Context.newBranchDB(consts.WITHDRAW_AMOUNT, BigInteger.class); + protected static final BranchDB> sponsorWithdrawAmount = Context.newBranchDB(consts.SPONSOR_WITHDRAW_AMOUNT, BigInteger.class); + protected static final BranchDB> remainingAmount = Context.newBranchDB(consts.REMAINING_AMOUNT, BigInteger.class); + protected static final BranchDB> sponsorRemainingAmount = Context.newBranchDB(consts.SPONSOR_REMAINING_AMOUNT, BigInteger.class); + protected static final BranchDB> installmentCount = Context.newBranchDB(consts.INSTALLMENT_COUNT, Integer.class); + protected static final BranchDB> sponsorRewardCount = Context.newBranchDB(consts.SPONSOR_REWARD_COUNT, Integer.class); + protected static final BranchDB> status = Context.newBranchDB(consts.STATUS, String.class); @@ -47,7 +48,8 @@ public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ sponsorRemainingAmount.at(prefix).set(_proposals.sponsor_reward); installmentCount.at(prefix).set(_proposals.project_duration); sponsorRewardCount.at(prefix).set(_proposals.project_duration); - status.at(prefix).set(_proposals.token); + token.at(prefix).set(_proposals.token); + status.at(prefix).set(_proposals.status); } public Map getDataFromProposalDB(String prefix){ diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/test.java b/CPSTreasury/src/main/java/com/iconloop/score/example/test.java deleted file mode 100644 index 35c4b1b0..00000000 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/test.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.iconloop.score.example; - -import java.nio.charset.StandardCharsets; -import java.util.Map; -import com.eclipsesource.json.Json; -import com.eclipsesource.json.JsonObject; - -public class test { - public static void main(String[] args) throws Exception { - // Create raw data. - String prefix = "proposal" + "|" + "10" + "|" + "proposal_key"; - byte[] prefix_byte = prefix.getBytes(); - System.out.println(prefix_byte); - } -} From a9ab073764f9b3cf90829b0309d29ea84384c493 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 21 Mar 2022 12:03:04 +0545 Subject: [PATCH 005/112] new changes --- .../iconloop/score/example/CPSTreasury.class | Bin 13182 -> 17827 bytes .../db/ProposalData$ProposalAttributes.class | Bin 695 -> 712 bytes .../score/example/db/ProposalData.class | Bin 4163 -> 4198 bytes .../com/iconloop/score/example/test.class | Bin 794 -> 0 bytes .../libs/CPSTreasury-0.9.1-optimized.jar | Bin 7656 -> 9063 bytes CPSTreasury/build/libs/CPSTreasury-0.9.1.jar | Bin 145292 -> 146562 bytes 6 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 CPSTreasury/build/classes/java/main/com/iconloop/score/example/test.class diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class index 367d79bc14ffae074c3aa31d7cb8bf322b808e6f..6e2506a9f63ef2a3e8f1815f3ecfdb131e31d851 100644 GIT binary patch literal 17827 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 delta 5284 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 diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData$ProposalAttributes.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData$ProposalAttributes.class index a23c57f08740f99eaf72125e500503eaf6f99f5b..5865de269c44a2f20d500949eff183ec83079747 100644 GIT binary patch delta 169 zcmdnadV*E-)W2Q(7#JAL85Fn}m>Fc)8D!ZRo;8AKSwfjnjg2_VVDAju#FrllFgfHW6S4HJVjgD3+h03G5K&Hw-a delta 144 zcmX@Xx}8<@)W2Q(7#JAL8RWSbm>Hzm8D!WQWG9L)nRw_bn;Z`V9|Qm7xs08R?32}* ztm7C#d2|sBpXFA}YJ9F3me)rnztjAt!|4{NvN#f_f z&V2{0;(R7+7>KZ%?NJ69vUwmvGdrTB^Pp}ID;-hvkfMhbjVc<;q@0~fA5pq1lPVrn zx?AaEiXM-!f+rL`sp2UWPpe2IR6e8PSv|c+(Q}HPw|T+lMTh+k;~K6h;U$c2#J-^{_#Nkbcw;bMfIO_0@!!d^rwS6~}_c-p*X>-EneH-h8 zsXw=;CvK(7WgRUxlP(|fkwtWD+sJ5td~@$;dz;ICdR#u{q)QtuE(iIMH>|z z=9J5)eCBeE(h0TroG)CiQ+h<{^@_e!iyIW(sNyCSOK(1`ptD*CbEnfP|I)BSrO{3Vj8S^8k4b< z%=zQrewE>oerdHTXtO%lU=7i3jkD1@PE)dXa_8g( z+D8jbqiEvqvT? zn_P;?lL^bGjshuBA)8n%k3o@4?GpM#JIqpcQ^FpW$z1e_afp8ImsKByW+^Ec*=v?! NuO%WDd)XI`{0-=GFs}dr delta 1783 zcmaKs`&U#|6vsbz2Ik(GxzKoUcx6DTh{GEU4GRIaf?kwmQBjdlX(b6gwAYlCriN+Q z(=010d#aaGuvM$I>W5Z;LH^cHt$ytvXtnp9yKZY@(ac)=e7|Sk{XF}eKWcue$^QEH zxgUVle3#%d?u)aA`;$DtR-0{cI(aZj0T1c+!%DX+8dLO$q8*CH6RcoD>7z;?OOWAl zrB5i`sc2W6Wjv|qDHTtvct%C`SzoGnPQQNM<^`LV9QHWu)zB~7>`Stn{SF6gUU8Uo zIB4^#!y#24ws}qCO*tHKc-`R*hc_MGa(LU}9fv;kd{iC0o8TDlISkmmZ*$z{0}C@S z6SYPPvNv**%N2CleCYBK(-z5zEo0-O&6|hEH}tyfVaVlUK5^-x%jE!{x~x|;sc3_u zgPd^rjL%)JRC-7)zTiujtCb#6+OOylewu})ZoZsAf>$a{rLWqDlc3;9OTOMxN3O1M;*$0d!BtAD8*D;osV z08)PVfpY0Y9+#%%acNJ;H38{V9+#$tyjzCCLJm~qCMmI5R!i2d!pvE$(|*x6i;VfZ zac&Xp`nZtI+$zlCHU_0NVr?CkH7aZM%#LK0mHpSeQ#uK?q-FFo)JbtG#W=$l_3WjA zqcn1oCVrL#&eOtQv|4f6tSZ|5kTp5CK}ZR}?cAYh2)dIY3453Lk4I!1+0d-+CVP)q zNm`MVq#u#J=~U78EE$ZNDvwD09MK3rQedj*s8MwBESGE=EHFzw>`?2mI8ZP1)rDrc zM|?qb%+z`$bLy-(kIqsQ*st*IZByq_9NN#Z(vr}bGt~QP$252>T2P&enMRM2Q2*cT zQnqRGDF2`MDaSN>RD>SpC76nv7LRoJ!MqR&)9O*Wus&(pJjz6$&GmPl1J|^BtO_0E z_kWg4Ps#a3(5dU<0+AgQ$%9)jFH^r<%B}M3?PDz`xSU_)a{ft|jLJGIL$}pWkF||n zYd`C)<77Mh*(uGPeKks%Od zo8AXO@YI5(;T1* zvpVonsaMMKdy~6TB_voZ|1?#U%Ec<9jdJNsg*-bOE9HH>P_D!hM!1OW^2tuBoY{q0=JP diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/test.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/test.class deleted file mode 100644 index e02fa07cc348496a1a05ee0399ef76269632bc5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 794 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 delta 4416 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 G0002^^KvEt diff --git a/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar b/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar index c97ff610cd280bfe053d69332c304abff3cd421c..271fdb35771c83d4249b0fb15eca6ad835847ec6 100644 GIT binary patch delta 11298 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 EKk=GrZU6uP From f4221fa75fe734c4911596e573efd848e00b3357 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 21 Mar 2022 14:19:31 +0545 Subject: [PATCH 006/112] completed translating the methods of CPS treasury --- .../iconloop/score/example/CPSTreasury.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java index 6c719658..909f7a76 100644 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java @@ -394,6 +394,103 @@ public void send_reward_to_sponsor(String _ipfs_key){ @External public void disqualify_project(String _ipfs_key){ + _validate_cps_score(); + Context.require(_proposal_exists(_ipfs_key), TAG + ": Project not found. Invalid IPFS hash."); + String prefix = proposal_prefix(_ipfs_key); + ProposalData.status.at(prefix).set(DISQUALIFIED); + + BigInteger totalBudget = ProposalData.totalBudget.at(prefix).getOrDefault(BigInteger.ZERO); + BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); + BigInteger sponsorReward = ProposalData.sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO); + BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); + String flag = ProposalData.token.at(prefix).get(); + + BigInteger remainingBudget = totalBudget.subtract(withdrawAmount); + BigInteger remainingReward = sponsorReward.subtract(sponsorWithdrawAmount); + BigInteger totalReturnAmount = remainingBudget.add(remainingReward); + + try{ + if (flag.equals(consts.ICX)){ + Context.call(totalReturnAmount, cpfTreasuryScore.get(), "disqualify_proposal_fund", _ipfs_key); + } + else if(flag.equals(consts.bnUSD)){ + String _data = "" + "{\"method\":\"disqualify_project\",\"params\":{\"ipfs_key\":" + "\"" + _ipfs_key + "\"" + "}}"; + Context.call(balancedDollar.get(), "transfer", cpfTreasuryScore.get(), totalReturnAmount, _data.getBytes()); + } + else{ + Context.revert(TAG + ": Not supported token."); + } + ProposalDisqualified(_ipfs_key, _ipfs_key + ", Proposal disqualified"); + } + catch (Exception e){ + Context.revert(TAG + ": Network problem. Sending proposal funds to CPF after project disqualification."); + } + } + + @External + public void claim_reward(){ + BigInteger availableAmountICX = installmentFundRecord.at(Context.getCaller().toString()).get(consts.ICX); + BigInteger availableAmountbnUSD = installmentFundRecord.at(Context.getCaller().toString()).get(consts.bnUSD); + if (availableAmountICX.compareTo(BigInteger.ZERO) > 0){ + try{ + installmentFundRecord.at(Context.getCaller().toString()).set(consts.ICX, BigInteger.ZERO); + Context.transfer(Context.getCaller(), availableAmountICX); + ProposalFundWithdrawn(Context.getCaller(), availableAmountICX + " " + consts.ICX + " withdrawn to " + Context.getCaller()); + } + catch (Exception e){ + Context.revert(TAG + ": Network problem while claiming reward."); + } + } + else if(availableAmountbnUSD.compareTo(BigInteger.ZERO) > 0){ + try { + installmentFundRecord.at(Context.getCaller().toString()).set(consts.bnUSD, BigInteger.ZERO); + Context.call(balancedDollar.get(), "transfer",Context.getCaller(), availableAmountbnUSD); + } + catch (Exception e){ + Context.revert(TAG + ": Network problem while claiming reward."); + } + } + else{ + Context.revert(TAG + ": Claim Reward Fails. Available amount(ICX) = " + availableAmountICX + " and Available amount(bnUSD) = " + availableAmountbnUSD); + } + } + + @External + public void tokenFallback(Address _from, BigInteger _value, byte[] _data){ + Context.require(_from.equals(cpfTreasuryScore.get()), TAG + "Only receiving from " + cpfTreasuryScore.get()); + String unpacked_data = new String(_data); + JsonObject jsonObject = Json.parse(unpacked_data).asObject(); + JsonObject params = jsonObject.get("params").asObject(); + if (jsonObject.get("method").asString().equals("deposit_proposal_fund")){ + String ipfs_hash = params.get("ipfs_hash").asString(); + int project_duration = Integer.parseInt(params.get("project_duration").asString()); + BigInteger total_budget = new BigInteger(params.get("total_budget").asString()); + BigInteger sponsor_reward = new BigInteger(params.get("sponsor_reward").asString()); + String token = params.get("token").asString(); + String contributor_address = params.get("contributor_address").asString(); + String sponsor_address = params.get("sponsor_address").asString(); + ProposalAttributes proposalAttributes = new ProposalAttributes(); + proposalAttributes.ipfs_hash = ipfs_hash; + proposalAttributes.project_duration = project_duration; + proposalAttributes.total_budget = total_budget; + proposalAttributes.sponsor_reward = sponsor_reward; + proposalAttributes.token = token; + proposalAttributes.contributor_address = contributor_address; + proposalAttributes.sponsor_address = sponsor_address; + proposalAttributes.status = ACTIVE; + _deposit_proposal_fund(proposalAttributes, _value); + } + else if (jsonObject.get("method").asString().equals("budget_adjustment")){ + String ipfs_key = params.get("_ipfs_key").asString(); + BigInteger added_budget = new BigInteger(params.get("_added_budget").asString()); + BigInteger added_sponsor_reward = new BigInteger(params.get("_added_sponsor_reward").asString()); + int added_installment_count = Integer.parseInt(params.get("_added_installment_count").asString()); + + update_proposal_fund(ipfs_key, added_budget, added_sponsor_reward, added_installment_count); + } + else{ + Context.revert(TAG + jsonObject.get("method").asString() + " Not a valid method."); + } } @@ -415,5 +512,7 @@ public void ProposalFundDeposited(String _ipfs_key, String note){} @EventLog(indexed = 1) public void ProposalFundSent(Address _receiver_address, String note){} + @EventLog(indexed = 1) + public void ProposalFundWithdrawn(Address _receiver_address, String note){} } From 763f77dc2a0cd58549538fe6024effc7786a86c9 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 21 Mar 2022 14:20:25 +0545 Subject: [PATCH 007/112] test file for testing java methods --- .../java/com/iconloop/score/example/test.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 CPSTreasury/src/main/java/com/iconloop/score/example/test.java diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/test.java b/CPSTreasury/src/main/java/com/iconloop/score/example/test.java new file mode 100644 index 00000000..78164ecb --- /dev/null +++ b/CPSTreasury/src/main/java/com/iconloop/score/example/test.java @@ -0,0 +1,15 @@ +package com.iconloop.score.example; + +import java.nio.charset.StandardCharsets; +import java.util.Map; +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonObject; + +public class test { + public static void main(String[] args) throws Exception { + // Create raw data. + String prefix = "proposal" + "|" + "10" + "|" + "proposal_key"; + byte[] prefix_byte = prefix.getBytes(); + System.out.println(prefix_byte); + } +} \ No newline at end of file From d2ad235419615072ab7c12d0e069f019e55ca710 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 21 Mar 2022 14:20:42 +0545 Subject: [PATCH 008/112] new changes --- .../com/iconloop/score/example/test.class | Bin 1306 -> 1973 bytes .../java/com/iconloop/score/example/test.java | 7 +++++-- .../iconloop/score/example/CPSTreasury.class | Bin 17827 -> 21733 bytes .../com/iconloop/score/example/test.class | Bin 0 -> 794 bytes .../libs/CPSTreasury-0.9.1-optimized.jar | Bin 9063 -> 30674 bytes CPSTreasury/build/libs/CPSTreasury-0.9.1.jar | Bin 146562 -> 149030 bytes 6 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 CPSTreasury/build/classes/java/main/com/iconloop/score/example/test.class diff --git a/CPFTreasury/build/classes/java/main/com/iconloop/score/example/test.class b/CPFTreasury/build/classes/java/main/com/iconloop/score/example/test.class index 38d988576c4b655d223ba28e30082f25498232ad..ed4c75e13a813d58bcfa52a5e746bb1492237377 100644 GIT binary patch literal 1973 zcmah~ZBr9h6n-uw*<@XLi6W)6A`#kP!KiJq2DELcRBS*j6ko8#OL7TIHoM#1jbp~~ zfAnv(AEIMt`UCo-I(=?JAQYs`u=kvE&w0*sUUu{MKkxnma1*|XbGVkK{Dp}GzD!{j zH%)wnTL$vlGN+Y!6Sr~4#Mk&HiL8llQP9dl65~mXnfMNOwcDbB?+x4&NX*-=9o-S= z%}#9y#1_1=66i15u3D+rwpFk$w;fv2MXw~C4H?*4-#5mhT{{#QFP6Mo&MtYb<9U8A zEO~*-sh6_mJ1Q5cFq$K9P1>%&h3sZ=Pri^jN4k~VS`^rBWv-Q21{Fe`JKN#*oS z?miz6w)a#?vrW`gwCgb{)ycdiU>?X?x%;xD{K)p)&;U6NEVm+7H8T~dfb7h*7W|^E z`?bG`9S})9uVmXWH}1evEu^Q&ynZb(T$5F`;JGCkJ+h-+ zN?|13i0vE7E=`>@-(*Eag$CQnnP#W-l)Kx~2qRVFHhcAm5bb!|%dK+JBCeZ~HIBDk z%Tcp{;cF*{OEQ%0O1!@mdP(Ei&4NCU+;=VUsBY|gc8k$$L&)~ecB6NqPg~0k>C_cz zUpfW8<->)SVP{~I*{Rb&4|aY06x0q@FMHksZ_^bxPw>Nq*e^n0@X)s8MyjF$MzzYO z`kub=<%x0B8wPgu?mGe#hbXrD!mFzN4@G-T7G){&f`$PODpB;jYTXyGmRwf_3yuu= zRtx;r-QsZH_^ND2Vyf##Q#L%$;=xV`4|l&u_lruvA0MyVdmo_@${J{ ztR~Lp6O{W}vYGDRw;3bGTMW!5890<|V(^gI4blP5Fqy^FXVHg#)-s4O*7qsvx=!sj z$vwm{9+Uoa($+;hYZJxCxJa#spSv+!VqqzIjUz)#AJ%Xg6D(;A1x(TwBic25Lfkkp zCy=ErLF55UQQ}vW(N~C)#An2e5p5bXl;VPEK%lFwR5?_6n!L7A!yXA;r=FyKga4oZ E3u`<1o&W#< delta 512 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 delta 6202 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 VDj*>K$$|9ynfSfAK~#U<{s%irKQ;gW diff --git a/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar b/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar index 271fdb35771c83d4249b0fb15eca6ad835847ec6..2d20fb22923bdb121b05e45c613bfddf0ba0cc6b 100644 GIT binary patch delta 11273 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 delta 8896 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 Date: Fri, 8 Apr 2022 12:07:48 +0545 Subject: [PATCH 009/112] removed unnecessary folders and files --- .../java/com/iconloop/score/example/test.java | 26 - CPSTreasury/build/libs/CPSTreasury-0.9.1.jar | Bin 149775 -> 164910 bytes .../iconloop/score/example/CPSTreasury.java | 518 ------------------ .../score/example/db/ProposalData.java | 72 --- .../java/com/iconloop/score/example/test.java | 15 - 5 files changed, 631 deletions(-) delete mode 100644 CPFTreasury/src/main/java/com/iconloop/score/example/test.java delete mode 100644 CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java delete mode 100644 CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java delete mode 100644 CPSTreasury/src/main/java/com/iconloop/score/example/test.java diff --git a/CPFTreasury/src/main/java/com/iconloop/score/example/test.java b/CPFTreasury/src/main/java/com/iconloop/score/example/test.java deleted file mode 100644 index 648f0ef1..00000000 --- a/CPFTreasury/src/main/java/com/iconloop/score/example/test.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.iconloop.score.example; - -import java.nio.charset.StandardCharsets; -import java.util.Map; -import com.eclipsesource.json.Json; -import com.eclipsesource.json.JsonObject; - -public class test { - public static void main(String[] args) throws Exception { - // Create raw data. - int ipfs_key = 0; - String params = "" + "{\"method\":\"disqualify_project\",\"params\":{\"ipfs_key\":" + "\"" + ipfs_key + "\"" + "}}"; - byte[] data = params.getBytes(); - - System.out.println(data); - - String unpacked = new String(data); - System.out.println(unpacked); - - JsonObject json = Json.parse(unpacked).asObject(); - String method = json.get("method").asString(); - String ipfs_key_ = json.get("params").asObject().get("ipfs_key").asString(); - int ipfs_key__ = Integer.parseInt(ipfs_key_); - System.out.println(ipfs_key__); - } -} diff --git a/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar b/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar index c34fb0f352d28d93cf4e622a604a53ed70b69ddf..4463b7c11dd787518050bff3762f787807d8f9be 100644 GIT binary patch delta 16608 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 OqhW%9In{r7a{fQZu>{)y delta 2425 zcmaKudr;I>6vuzRv&eIUjbW9CO9%?Kuz@xpETVv57J@V~kt_(xg1jHf!{z;$CalDv zU&9$k!O^ku{TRqhZL%`Q9#&3TYGW2=DTtLgLQZPu{C=>w{n0YB=bq1b+;i{u4sf8u zdDELt>eM8aowFb~ItoLkE_D#lcX%@lnxx*S*=){48Q6?Q&0(WA&SR5nT*PLV@p&?R zBgRNzYlt~&&-V94ks{j}i61$!9Z2c*Co8p8E@t|0Tzv17G9qWU8g*xy^Wf# z8#*?URt#X<-q!ejTcg-~g{DH43BuVLO%Q7wGiCWy44Qggvm_;!239&7=-FDW* zt^#jc&ILjLTM%qh(9Z=1Y{^k}?aZNFAIVG#i*~~s#QpfBub#hsJlkFnyj=w$#@ay; z`dg#yxPw#_<1T0O?5kE$ml0>V^S)K!DR1fg9k2=i<@7}S&*g>G5O48g0Z z`nHx>5LT>KZfFy;&PZmV=GFhX&yKW(tDBCA4uY^lBM3&D-rvhLsLzENJXvxs^$CsT zK2nBdHXh4W_B_KpE?(aA2{Q!ZYbH=T4ac=4$TDJ<8FYApnB8#P&IJ6*1U^_~1`QUF zT*S^LU{@w+ae5}GmB4N#V3#NdBu$e&t~7%lVywUg_b{lp0&RC5`NroaD%>zNj~?7u zsuf6EH@M>QQg{MS=h4MPET4>AetkSrOryf+OA`?%T$K+Y5S~5>_UA(cTz%OJq{gl% z(UeE0DKpdfVQat@26L@pT)74e@U(dn7lSX%>|}_`iXjX#y0Ntw(!g#rTYvnUVfYR?VMz(h1LpdLKih>Kdpl?y_9w^AENb4$?>KKtDuLWKH1-NOD*px<^SQKo_KycTgQ%2 zGywC(xNqv9J?dxEPN~adFH$j|+hDK`VRz(-#=Z2wG5D81&u%{8`;ueOd zwD@xqcw%OX=!BXk%Dut(A1?*_Rg+*tzU(}O`9araTb#~c!ixP13T03+dR=8 zQ<|woU=86r3vqD`B&dAjMch^=&cFjTB<7_gyj%lI;jc8DT?+{?e+8D+LMHr@$u<~= zy}3AFHWNMOw17M2ucwY7`AocU+j_c8mjXPu9+F^wDO(?mve40L%N3{7LeDv7 z9XnI;k_G0&*;>Uh)Y03%W>K7$I#T>rgW`m?!xX&Q2HrSaN1Lgdt=JQz>xp!?GSOm1 zJ%p)(-V*U(JN*v(oI|Xr^l{tAc4YqL_B;!oUTZDvI*=kuYq3C*S*-<0P(84 z?UMqkQI3yrJop{fPOp%dM(|eM-7~481`B@^HJDWe&M>;4B}|3#enqAU_4M%WQH79j zUP>d!dsLNNO;z0=a!l57E?obVon`Rrmux51(?icse9a4#>J!a0Sp0ykIO9Wmw@^%b z-6~TUY#g#GZ@P}QVgDXpkPv0r{E0636B&^I(sU37vp5W=2mJlp?D;i?W`mMM(x>=bsj&&{TFR! k>+r$@?U1P2<_ogwQ&W?s&|hsqu+UFIpdfVl^ZzUV0ygvx)Bpeg diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java b/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java deleted file mode 100644 index 909f7a76..00000000 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/CPSTreasury.java +++ /dev/null @@ -1,518 +0,0 @@ -/* - * Copyright 2020 ICONLOOP Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iconloop.score.example; - -import com.iconloop.score.example.db.ProposalData; -import score.*; -import com.eclipsesource.json.Json; -import com.eclipsesource.json.JsonObject; -import score.annotation.EventLog; -import score.annotation.External; -import score.annotation.Payable; -import scorex.util.ArrayList; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Map; - -import com.iconloop.score.example.utils.consts; - -public class CPSTreasury extends ProposalData{ - private final String name; - private final String symbol; - private static final String TAG = "CPS_Treasury"; - private static final String PROPOSAL_DB_PREFIX = "proposal"; - - private static final String ID = "id"; - private static final String PROPOSALS_KEYS = "_proposals_keys"; - private static final String PROPOSALS_KEY_LIST_INDEX = "proposals_key_list_index"; - private static final String FUND_RECORD = "fund_record"; - private static final String INSTALLMENT_FUND_RECORD = "installment_fund_record"; - - private static final String TOTAL_INSTALLMENT_COUNT = "_total_installment_count"; - private static final String TOTAL_TIMES_INSTALLMENT_PAID = "_total_times_installment_paid"; - private static final String TOTAL_TIMES_REWARD_PAID = "_total_times_reward_paid"; - private static final String TOTAL_INSTALLMENT_PAID = "_total_installment_paid"; - private static final String TOTAL_REWARD_PAID = "_total_reward_paid"; - private static final String INSTALLMENT_AMOUNT = "installment_amount"; - private static final String SPONSOR_BOND_AMOUNT = "sponsor_bond_amount"; - private static final String CPS_SCORE = "_cps_score"; - private static final String CPF_TREASURY_SCORE = "_cpf_treasury_score"; - private static final String BALANCED_DOLLAR = "balanced_dollar"; - - private static final String SPONSOR_ADDRESS = "sponsor_address"; - private static final String CONTRIBUTOR_ADDRESS = "contributor_address"; - private static final String STATUS = "status"; - private static final String IPFS_HASH = "ipfs_hash"; - private static final String SPONSOR_REWARD = "sponsor_reward"; - private static final String TOTAL_BUDGET = "total_budget"; - - private static final String ACTIVE = "active"; - private static final String DISQUALIFIED = "disqualified"; - private static final String COMPLETED = "completed"; - - - private static final VarDB id = Context.newVarDB(ID, String.class); - private static final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); - private static final DictDB proposalsKeyListIndex = Context.newDictDB(PROPOSALS_KEY_LIST_INDEX, Integer.class); - private static final DictDB fundRecord = Context.newDictDB(FUND_RECORD, BigInteger.class); - private static final BranchDB> installmentFundRecord = Context.newBranchDB(INSTALLMENT_FUND_RECORD, BigInteger.class); - - private static final VarDB

cpfTreasuryScore = Context.newVarDB(CPF_TREASURY_SCORE, Address.class); - private static final VarDB
cpsScore = Context.newVarDB(CPS_SCORE, Address.class); - private static final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); - - public CPSTreasury(String name, String symbol){ - this.name=name; - this.symbol=symbol; - } - - @External(readonly = true) - public String name(){ - return this.name; - } - - @External(readonly = true) - public String symbol(){ - return this.symbol; - } - - @Payable - public void fallback(){ - Context.revert(TAG + ": ICX can only be send by CPF Treasury Score"); - } - - private void set_id(String _val){ - id.set(_val); - } - - private String get_id(){ - return id.get(); - } - - private String proposal_prefix(String _proposal_key){ - return PROPOSAL_DB_PREFIX + "|" + id.get() + "|" + _proposal_key; - } - - private Boolean _proposal_exists(String _ipfs_key){ - return proposalsKeyListIndex.getOrDefault(_ipfs_key, null) != null; - } - - private void _validate_admins(){ - Context.require((Boolean) Context.call(cpsScore.get(), "is_admin", Context.getCaller()), - TAG + ": Only admins can call this method"); - - } - - private void _validate_owner(){ - Context.require(Context.getCaller().equals(Context.getOwner()), - TAG + ": Only owner can call this method"); - } - - private void _validate_owner_score(Address _score){ - _validate_owner(); - Context.require(_score.isContract(), TAG + "Target " + _score + " is not a score."); - } - - private void _validate_cps_score(){ - Context.require(Context.getCaller().equals(cpsScore.get()), - TAG + ": Only CPS score " + cpsScore.get() + " can send fund using this method."); - } - - private void _validate_cpf_treasury_score(){ - Context.require(Context.getCaller().equals(cpfTreasuryScore.get()), - TAG + ": Only CPF Treasury score " + cpfTreasuryScore.get() + " can send fund using this method."); - } - - private void _add_record(ProposalData.ProposalAttributes _proposal){ - ProposalData proposalData = new ProposalData(); - String ipfs_hash = _proposal.ipfs_hash; - Context.require(!_proposal_exists(ipfs_hash), TAG + ": Already have this project"); - proposalsKeys.add(ipfs_hash); - proposalData.addDataToProposalDB(_proposal, ipfs_hash); - proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); - } - - private Map _get_projects(String _proposal_key){ - ProposalData proposalData = new ProposalData(); - return proposalData.getDataFromProposalDB(_proposal_key); - } - - @External - public void set_cps_score(Address _score){ - _validate_owner_score(_score); - cpsScore.set(_score); - } - - @External(readonly = true) - public Address get_cps_score(){ - return cpsScore.get(); - } - - @External - public void set_cpf_treasury_score(Address _score){ - _validate_owner_score(_score); - cpfTreasuryScore.set(_score); - } - - @External(readonly = true) - public Address get_cpf_treasury_score(){ - return cpfTreasuryScore.get(); - } - - @External - public void set_bnUSD_score(Address _score){ - _validate_owner_score(_score); - balancedDollar.set(_score); - } - - @External - public Address get_bnUSD_score(){ - return balancedDollar.get(); - } - - @External(readonly = true) - public Map get_contributor_projected_fund(Address _wallet_address){ - ProposalData proposalData = new ProposalData(); - BigInteger totalAmountToBePaidICX = BigInteger.ZERO; - BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; - List> projectDetails = new ArrayList<>(); - for (int i = 0; i < proposalsKeys.size(); i++){ - String _ipfs_key = proposalsKeys.get(i); - Map proposal_details = proposalData.getDataFromProposalDB(_ipfs_key); - if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)){ - if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())){ - int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); - int totalPaidCount = (int) proposal_details.get(consts.INSTALLMENT_COUNT); - if (totalPaidCount < totalInstallment){ - String flag = (String) proposal_details.get(consts.TOKEN); - BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); - BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); - - Map project_details = Map.of( - consts.IPFS_HASH, _ipfs_key, - consts.TOKEN, flag, - consts.TOTAL_BUDGET, totalBudget.toString(), - consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount.toString(), - consts.TOTAL_INSTALLMENT_COUNT, String.valueOf(totalInstallment), - consts.TOTAL_TIMES_INSTALLMENT_PAID, String.valueOf(totalPaidCount), - consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)).toString()); - - projectDetails.add(project_details); - if (flag.equals(consts.ICX)){ - totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - } - else { - totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - } - } - } - } - } - return Map.of( - "data", projectDetails, - "project_count", projectDetails.size(), - "total_amount", Map.of("ICX", totalAmountToBePaidICX, "bnUSD", totalAmountToBePaidbnUSD), - "withdraw_amount_icx", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.ICX, BigInteger.ZERO), - "withdraw_amount_bnUSD", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.bnUSD, BigInteger.ZERO)); - } - - - @External(readonly = true) - public Map get_sponsor_projected_fund(Address _wallet_address){ - ProposalData proposalData = new ProposalData(); - BigInteger totalAmountToBePaidICX = BigInteger.ZERO; - BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; - BigInteger totalSponsorBondICX = BigInteger.ZERO; - BigInteger totalSponsorBondbnUSD = BigInteger.ZERO; - List> projectDetails = new ArrayList<>(); - for (int i = 0; i < proposalsKeys.size(); i++){ - String _ipfs_key = proposalsKeys.get(i); - Map proposal_details = proposalData.getDataFromProposalDB(_ipfs_key); - if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)){ - if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())){ - int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); - int totalPaidCount = (int) proposal_details.get(consts.INSTALLMENT_COUNT); - if (totalPaidCount < totalInstallment){ - String flag = (String) proposal_details.get(consts.TOKEN); - BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); - BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); - BigInteger depositedSponsorBond = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); - - Map project_details = Map.of( - consts.IPFS_HASH, _ipfs_key, - consts.TOKEN, flag, - consts.TOTAL_BUDGET, totalBudget.toString(), - consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount.toString(), - consts.TOTAL_INSTALLMENT_COUNT, String.valueOf(totalInstallment), - consts.TOTAL_TIMES_INSTALLMENT_PAID, String.valueOf(totalPaidCount), - consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)).toString(), - consts.SPONSOR_BOND_AMOUNT, depositedSponsorBond.toString()); - - projectDetails.add(project_details); - if (flag.equals(consts.ICX)){ - totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - totalSponsorBondICX = totalSponsorBondICX.add(depositedSponsorBond); - } - else { - totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - totalSponsorBondbnUSD = totalSponsorBondbnUSD.add(depositedSponsorBond); - } - } - } - } - } - return Map.of( - "data", projectDetails, - "project_count", projectDetails.size(), - "total_amount", Map.of("ICX", totalAmountToBePaidICX, "bnUSD", totalAmountToBePaidbnUSD), - "withdraw_amount_icx", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.ICX, BigInteger.ZERO), - "withdraw_amount_bnUSD", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.bnUSD, BigInteger.ZERO), - "total_sponsor_bond", Map.of("ICX", totalSponsorBondICX, "bnUSD", totalSponsorBondbnUSD) - ); - } - - private void _deposit_proposal_fund(ProposalData.ProposalAttributes _proposals, BigInteger _value){ - _add_record(_proposals); - ProposalFundDeposited(_proposals.ipfs_hash, "Received " + _proposals.ipfs_hash + " " + _value + " " + - consts.bnUSD + " fund from CPF"); - } - - @External - @Payable - public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, BigInteger _added_sponsor_reward, - int _added_installment_count){ - ProposalData proposalData = new ProposalData(); - Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS hash."); - String proposalPrefix = proposal_prefix(_ipfs_key); - Map proposalDetails = proposalData.getDataFromProposalDB(proposalPrefix); - BigInteger totalBudget = (BigInteger) proposalDetails.get(consts.TOTAL_BUDGET); - BigInteger sponsorReward = (BigInteger) proposalDetails.get(consts.SPONSORS_REWARDS); - int totalDuration = (int) proposalDetails.get(consts.PROJECT_DURATION); - BigInteger remainingAmount = (BigInteger) proposalDetails.get(consts.REMAINING_AMOUNT); - BigInteger sponsorRemainingAmount = (BigInteger) proposalDetails.get(consts.SPONSOR_REMAINING_AMOUNT); - int installmentCount = (int) proposalDetails.get(consts.INSTALLMENT_COUNT); - int sponsorRewardCount = (int) proposalDetails.get(consts.SPONSOR_REWARD_COUNT); - String flag = (String) proposalDetails.get(consts.TOKEN); - - ProposalData.totalBudget.at(proposalPrefix).set(totalBudget.add(_added_budget)); - ProposalData.sponsorReward.at(proposalPrefix).set(sponsorReward.add(_added_sponsor_reward)); - ProposalData.projectDuration.at(proposalPrefix).set(totalDuration + _added_installment_count); - ProposalData.remainingAmount.at(proposalPrefix).set(remainingAmount.add(_added_budget)); - ProposalData.sponsorRemainingAmount.at(proposalPrefix).set(sponsorRemainingAmount.add(_added_sponsor_reward)); - ProposalData.installmentCount.at(proposalPrefix).set(installmentCount + _added_installment_count); - ProposalData.sponsorRewardCount.at(proposalPrefix).set(sponsorRewardCount + _added_installment_count); - - ProposalFundDeposited(_ipfs_key, _ipfs_key + ": Added Budget: " + _added_budget + " " + - flag + "and Added time: " + _added_installment_count + " Successfully"); - } - - @External - public void send_installment_to_contributor(String _ipfs_key){ - _validate_cps_score(); - Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS Hash."); - BigInteger installmentAmount = BigInteger.ZERO; - ProposalData proposalData = new ProposalData(); - String prefix = proposal_prefix(_ipfs_key); - - int installmentCount = ProposalData.installmentCount.at(prefix).getOrDefault(0); - BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger remainingAmount = ProposalData.remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); - Address contributorAddress = ProposalData.contributorAddress.at(prefix).get(); - String flag = ProposalData.token.at(prefix).get(); - - try { - if (installmentCount == 1) { - installmentAmount = remainingAmount; - } else { - installmentAmount = remainingAmount.divide(BigInteger.valueOf(installmentCount)); - } - int newInstallmentCount = installmentCount - 1; - ProposalData.installmentCount.at(prefix).set(newInstallmentCount); - ProposalData.remainingAmount.at(prefix).set(remainingAmount.subtract(installmentAmount)); - ProposalData.withdrawAmount.at(prefix).set(withdrawAmount.add(installmentAmount)); - installmentFundRecord.at(contributorAddress.toString()).set(flag, - installmentFundRecord.at(contributorAddress.toString()).get(flag).add(installmentAmount)); - ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); - - if (newInstallmentCount == 0){ - ProposalData.status.at(prefix).set(COMPLETED); - } - } - catch (Exception e){ - Context.revert(TAG + ": Network problem. Sending project funds to contributor. " + e); - } - } - - @External - public void send_reward_to_sponsor(String _ipfs_key){ - _validate_cps_score(); - - Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS Hash."); - BigInteger installmentAmount = BigInteger.ZERO; - String prefix = proposal_prefix(_ipfs_key); - - int sponsorRewardCount = ProposalData.sponsorRewardCount.at(prefix).getOrDefault(0); - BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger sponsorRemainingAmount = ProposalData.sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); - Address sponsorAddress = ProposalData.sponsorAddress.at(prefix).get(); - String flag = ProposalData.token.at(prefix).get(); - - try { - if (sponsorRewardCount == 1) { - installmentAmount = sponsorRemainingAmount; - } else { - installmentAmount = sponsorRemainingAmount.divide(BigInteger.valueOf(sponsorRewardCount)); - } - int newSponsorRewardCount = sponsorRewardCount - 1; - ProposalData.sponsorRewardCount.at(prefix).set(newSponsorRewardCount); - ProposalData.sponsorWithdrawAmount.at(prefix).set(sponsorWithdrawAmount.add(installmentAmount)); - ProposalData.sponsorRemainingAmount.at(prefix).set(sponsorRemainingAmount.subtract(installmentAmount)); - installmentFundRecord.at(sponsorAddress.toString()).set(flag, installmentFundRecord.at(sponsorAddress.toString()).get(flag).add(installmentAmount)); - ProposalFundSent(sponsorAddress, "New installment " + installmentAmount + " " + - flag + " sent to sponsor address."); - } - catch (Exception e){ - Context.revert(TAG + ": Network problem. Sending project funds to sponsor."); - } - } - - @External - public void disqualify_project(String _ipfs_key){ - _validate_cps_score(); - Context.require(_proposal_exists(_ipfs_key), TAG + ": Project not found. Invalid IPFS hash."); - String prefix = proposal_prefix(_ipfs_key); - ProposalData.status.at(prefix).set(DISQUALIFIED); - - BigInteger totalBudget = ProposalData.totalBudget.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger sponsorReward = ProposalData.sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); - String flag = ProposalData.token.at(prefix).get(); - - BigInteger remainingBudget = totalBudget.subtract(withdrawAmount); - BigInteger remainingReward = sponsorReward.subtract(sponsorWithdrawAmount); - BigInteger totalReturnAmount = remainingBudget.add(remainingReward); - - try{ - if (flag.equals(consts.ICX)){ - Context.call(totalReturnAmount, cpfTreasuryScore.get(), "disqualify_proposal_fund", _ipfs_key); - } - else if(flag.equals(consts.bnUSD)){ - String _data = "" + "{\"method\":\"disqualify_project\",\"params\":{\"ipfs_key\":" + "\"" + _ipfs_key + "\"" + "}}"; - Context.call(balancedDollar.get(), "transfer", cpfTreasuryScore.get(), totalReturnAmount, _data.getBytes()); - } - else{ - Context.revert(TAG + ": Not supported token."); - } - ProposalDisqualified(_ipfs_key, _ipfs_key + ", Proposal disqualified"); - } - catch (Exception e){ - Context.revert(TAG + ": Network problem. Sending proposal funds to CPF after project disqualification."); - } - } - - @External - public void claim_reward(){ - BigInteger availableAmountICX = installmentFundRecord.at(Context.getCaller().toString()).get(consts.ICX); - BigInteger availableAmountbnUSD = installmentFundRecord.at(Context.getCaller().toString()).get(consts.bnUSD); - if (availableAmountICX.compareTo(BigInteger.ZERO) > 0){ - try{ - installmentFundRecord.at(Context.getCaller().toString()).set(consts.ICX, BigInteger.ZERO); - Context.transfer(Context.getCaller(), availableAmountICX); - ProposalFundWithdrawn(Context.getCaller(), availableAmountICX + " " + consts.ICX + " withdrawn to " + Context.getCaller()); - } - catch (Exception e){ - Context.revert(TAG + ": Network problem while claiming reward."); - } - } - else if(availableAmountbnUSD.compareTo(BigInteger.ZERO) > 0){ - try { - installmentFundRecord.at(Context.getCaller().toString()).set(consts.bnUSD, BigInteger.ZERO); - Context.call(balancedDollar.get(), "transfer",Context.getCaller(), availableAmountbnUSD); - } - catch (Exception e){ - Context.revert(TAG + ": Network problem while claiming reward."); - } - } - else{ - Context.revert(TAG + ": Claim Reward Fails. Available amount(ICX) = " + availableAmountICX + " and Available amount(bnUSD) = " + availableAmountbnUSD); - } - } - - @External - public void tokenFallback(Address _from, BigInteger _value, byte[] _data){ - Context.require(_from.equals(cpfTreasuryScore.get()), TAG + "Only receiving from " + cpfTreasuryScore.get()); - String unpacked_data = new String(_data); - JsonObject jsonObject = Json.parse(unpacked_data).asObject(); - JsonObject params = jsonObject.get("params").asObject(); - if (jsonObject.get("method").asString().equals("deposit_proposal_fund")){ - String ipfs_hash = params.get("ipfs_hash").asString(); - int project_duration = Integer.parseInt(params.get("project_duration").asString()); - BigInteger total_budget = new BigInteger(params.get("total_budget").asString()); - BigInteger sponsor_reward = new BigInteger(params.get("sponsor_reward").asString()); - String token = params.get("token").asString(); - String contributor_address = params.get("contributor_address").asString(); - String sponsor_address = params.get("sponsor_address").asString(); - ProposalAttributes proposalAttributes = new ProposalAttributes(); - proposalAttributes.ipfs_hash = ipfs_hash; - proposalAttributes.project_duration = project_duration; - proposalAttributes.total_budget = total_budget; - proposalAttributes.sponsor_reward = sponsor_reward; - proposalAttributes.token = token; - proposalAttributes.contributor_address = contributor_address; - proposalAttributes.sponsor_address = sponsor_address; - proposalAttributes.status = ACTIVE; - _deposit_proposal_fund(proposalAttributes, _value); - } - else if (jsonObject.get("method").asString().equals("budget_adjustment")){ - String ipfs_key = params.get("_ipfs_key").asString(); - BigInteger added_budget = new BigInteger(params.get("_added_budget").asString()); - BigInteger added_sponsor_reward = new BigInteger(params.get("_added_sponsor_reward").asString()); - int added_installment_count = Integer.parseInt(params.get("_added_installment_count").asString()); - - update_proposal_fund(ipfs_key, added_budget, added_sponsor_reward, added_installment_count); - } - else{ - Context.revert(TAG + jsonObject.get("method").asString() + " Not a valid method."); - } - - } - - @EventLog(indexed = 1) - public void FundReturned(Address _sponsor_address, String note){} - - @EventLog(indexed = 1) - public void ProposalFundTransferred(String _ipfs_key, String note){} - - @EventLog(indexed = 1) - public void ProposalDisqualified(String _ipfs_key, String note){} - - @EventLog(indexed = 1) - public void FundReceived(Address _sponsor_address, String note){} - - @EventLog(indexed = 1) - public void ProposalFundDeposited(String _ipfs_key, String note){} - - @EventLog(indexed = 1) - public void ProposalFundSent(Address _receiver_address, String note){} - - @EventLog(indexed = 1) - public void ProposalFundWithdrawn(Address _receiver_address, String note){} - -} diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java b/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java deleted file mode 100644 index 12d9f558..00000000 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/db/ProposalData.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.iconloop.score.example.db; - -import score.*; -import com.iconloop.score.example.utils.consts; - -import java.math.BigInteger; -import java.util.Map; - -public class ProposalData { - public static class ProposalAttributes{ - public String ipfs_hash; - public int project_duration; - public BigInteger total_budget; - public BigInteger sponsor_reward; - public String token; - public String contributor_address; - public String sponsor_address; - public String status; - } - protected static final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); - protected static final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); - protected static final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSORS_REWARDS, BigInteger.class); - protected static final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); - protected static final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); - protected static final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); - protected static final BranchDB> token = Context.newBranchDB(consts.TOKEN, String.class); - protected static final BranchDB> withdrawAmount = Context.newBranchDB(consts.WITHDRAW_AMOUNT, BigInteger.class); - protected static final BranchDB> sponsorWithdrawAmount = Context.newBranchDB(consts.SPONSOR_WITHDRAW_AMOUNT, BigInteger.class); - protected static final BranchDB> remainingAmount = Context.newBranchDB(consts.REMAINING_AMOUNT, BigInteger.class); - protected static final BranchDB> sponsorRemainingAmount = Context.newBranchDB(consts.SPONSOR_REMAINING_AMOUNT, BigInteger.class); - protected static final BranchDB> installmentCount = Context.newBranchDB(consts.INSTALLMENT_COUNT, Integer.class); - protected static final BranchDB> sponsorRewardCount = Context.newBranchDB(consts.SPONSOR_REWARD_COUNT, Integer.class); - protected static final BranchDB> status = Context.newBranchDB(consts.STATUS, String.class); - - - - - public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ - ipfsHash.at(prefix).set(_proposals.ipfs_hash); - totalBudget.at(prefix).set(_proposals.total_budget); - sponsorReward.at(prefix).set(_proposals.sponsor_reward); - projectDuration.at(prefix).set(_proposals.project_duration); - sponsorAddress.at(prefix).set(Address.fromString(_proposals.sponsor_address)); - contributorAddress.at(prefix).set(Address.fromString(_proposals.contributor_address)); - withdrawAmount.at(prefix).set(BigInteger.ZERO); - sponsorWithdrawAmount.at(prefix).set(BigInteger.ZERO); - remainingAmount.at(prefix).set(_proposals.total_budget); - sponsorRemainingAmount.at(prefix).set(_proposals.sponsor_reward); - installmentCount.at(prefix).set(_proposals.project_duration); - sponsorRewardCount.at(prefix).set(_proposals.project_duration); - token.at(prefix).set(_proposals.token); - status.at(prefix).set(_proposals.status); - } - - public Map getDataFromProposalDB(String prefix){ - return Map.ofEntries( - Map.entry(consts.IPFS_HASH, ipfsHash.at(prefix).getOrDefault("")), - Map.entry(consts.TOTAL_BUDGET, totalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(consts.SPONSORS_REWARDS, sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(consts.PROJECT_DURATION, projectDuration.at(prefix).getOrDefault(0)), - Map.entry(consts.SPONSOR_ADDRESS, sponsorAddress.at(prefix).get().toString()), - Map.entry(consts.CONTRIBUTOR_ADDRESS, contributorAddress.at(prefix).get().toString()), - Map.entry(consts.WITHDRAW_AMOUNT, withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(consts.INSTALLMENT_COUNT, installmentCount.at(prefix).getOrDefault(0)), - Map.entry(consts.SPONSOR_REWARD_COUNT, sponsorRewardCount.at(prefix).getOrDefault(0)), - Map.entry(consts.SPONSOR_WITHDRAW_AMOUNT, sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(consts.REMAINING_AMOUNT, remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(consts.SPONSOR_REMAINING_AMOUNT, sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(consts.TOKEN, token.at(prefix).getOrDefault("")) - ); - } -} diff --git a/CPSTreasury/src/main/java/com/iconloop/score/example/test.java b/CPSTreasury/src/main/java/com/iconloop/score/example/test.java deleted file mode 100644 index 78164ecb..00000000 --- a/CPSTreasury/src/main/java/com/iconloop/score/example/test.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.iconloop.score.example; - -import java.nio.charset.StandardCharsets; -import java.util.Map; -import com.eclipsesource.json.Json; -import com.eclipsesource.json.JsonObject; - -public class test { - public static void main(String[] args) throws Exception { - // Create raw data. - String prefix = "proposal" + "|" + "10" + "|" + "proposal_key"; - byte[] prefix_byte = prefix.getBytes(); - System.out.println(prefix_byte); - } -} \ No newline at end of file From 37aefb96ede22cf1cd548086a8faadbcaf3640b6 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 8 Apr 2022 12:25:36 +0545 Subject: [PATCH 010/112] gitignore changes --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e24ca91f..874ffd88 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ gradle.properties keystore.zip lib CPSTreasury.iml +CPFTreasury/build +CPSTreasury/build \ No newline at end of file From f5c28e7f24cfb8a7290343a5bd397b773142c852 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 8 Apr 2022 12:31:33 +0545 Subject: [PATCH 011/112] removed build files from the repo --- .../com/iconloop/score/example/test.class | Bin 1973 -> 0 bytes .../cps/score/CPFTreasury/CPFTreasury.class | Bin 19139 -> 0 bytes .../CPFTreasury/utils/ArrayDBUtils.class | Bin 3610 -> 0 bytes .../score/CPFTreasury/utils/Eventlogs.class | Bin 1065 -> 0 bytes .../score/CPFTreasury/CPFTTreasuryTest.class | Bin 21411 -> 0 bytes .../libs/CPFTreasury-0.9.1-optimized.jar | Bin 28963 -> 0 bytes CPFTreasury/build/libs/CPFTreasury-0.9.1.jar | Bin 11843 -> 0 bytes ...ps.score.CPFTreasury.CPFTTreasuryTest.html | 879 ------------------ .../reports/tests/test/css/base-style.css | 179 ---- .../build/reports/tests/test/css/style.css | 84 -- .../build/reports/tests/test/index.html | 133 --- .../build/reports/tests/test/js/report.js | 194 ---- .../community.icon.cps.score.CPFTreasury.html | 103 -- ...cps.score.CPFTreasury.CPFTTreasuryTest.xml | 684 -------------- .../build/test-results/test/binary/output.bin | Bin 67481 -> 0 bytes .../test-results/test/binary/output.bin.idx | Bin 333 -> 0 bytes .../test-results/test/binary/results.bin | Bin 1328 -> 0 bytes CPFTreasury/build/tmp/jar/MANIFEST.MF | 2 - .../build/tmp/optimizedJar/MANIFEST.MF | 3 - .../iconloop/score/example/CPSTreasury.class | Bin 21733 -> 0 bytes .../db/ProposalData$ProposalAttributes.class | Bin 712 -> 0 bytes .../score/example/db/ProposalData.class | Bin 4198 -> 0 bytes .../com/iconloop/score/example/test.class | Bin 794 -> 0 bytes .../iconloop/score/example/utils/consts.class | Bin 5487 -> 0 bytes .../cps/score/CPSTreasury/CPSTreasury.class | Bin 21833 -> 0 bytes .../db/ProposalData$ProposalAttributes.class | Bin 742 -> 0 bytes .../score/CPSTreasury/db/ProposalData.class | Bin 4258 -> 0 bytes .../icon/cps/score/CPSTreasury/test.class | Bin 814 -> 0 bytes .../CPSTreasury/utils/ArrayDBUtils.class | Bin 3610 -> 0 bytes .../cps/score/CPSTreasury/utils/Checks.class | Bin 329 -> 0 bytes .../score/CPSTreasury/utils/Eventlogs.class | Bin 1022 -> 0 bytes .../cps/score/CPSTreasury/utils/consts.class | Bin 5507 -> 0 bytes .../libs/CPFTreasury-0.9.1-optimized.jar | Bin 28669 -> 0 bytes CPSTreasury/build/libs/CPFTreasury-0.9.1.jar | Bin 145351 -> 0 bytes .../libs/CPSTreasury-0.9.1-optimized.jar | Bin 30631 -> 0 bytes CPSTreasury/build/libs/CPSTreasury-0.9.1.jar | Bin 164910 -> 0 bytes .../build/libs/irc2-token-0.9.1-optimized.jar | Bin 28280 -> 0 bytes CPSTreasury/build/libs/irc2-token-0.9.1.jar | Bin 144816 -> 0 bytes CPSTreasury/build/tmp/jar/MANIFEST.MF | 2 - .../build/tmp/optimizedJar/MANIFEST.MF | 3 - 40 files changed, 2266 deletions(-) delete mode 100644 CPFTreasury/build/classes/java/main/com/iconloop/score/example/test.class delete mode 100644 CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/CPFTreasury.class delete mode 100644 CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/utils/ArrayDBUtils.class delete mode 100644 CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/utils/Eventlogs.class delete mode 100644 CPFTreasury/build/classes/java/test/community/icon/cps/score/CPFTreasury/CPFTTreasuryTest.class delete mode 100644 CPFTreasury/build/libs/CPFTreasury-0.9.1-optimized.jar delete mode 100644 CPFTreasury/build/libs/CPFTreasury-0.9.1.jar delete mode 100644 CPFTreasury/build/reports/tests/test/classes/community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.html delete mode 100644 CPFTreasury/build/reports/tests/test/css/base-style.css delete mode 100644 CPFTreasury/build/reports/tests/test/css/style.css delete mode 100644 CPFTreasury/build/reports/tests/test/index.html delete mode 100644 CPFTreasury/build/reports/tests/test/js/report.js delete mode 100644 CPFTreasury/build/reports/tests/test/packages/community.icon.cps.score.CPFTreasury.html delete mode 100644 CPFTreasury/build/test-results/test/TEST-community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.xml delete mode 100644 CPFTreasury/build/test-results/test/binary/output.bin delete mode 100644 CPFTreasury/build/test-results/test/binary/output.bin.idx delete mode 100644 CPFTreasury/build/test-results/test/binary/results.bin delete mode 100644 CPFTreasury/build/tmp/jar/MANIFEST.MF delete mode 100644 CPFTreasury/build/tmp/optimizedJar/MANIFEST.MF delete mode 100644 CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class delete mode 100644 CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData$ProposalAttributes.class delete mode 100644 CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData.class delete mode 100644 CPSTreasury/build/classes/java/main/com/iconloop/score/example/test.class delete mode 100644 CPSTreasury/build/classes/java/main/com/iconloop/score/example/utils/consts.class delete mode 100644 CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/CPSTreasury.class delete mode 100644 CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/db/ProposalData$ProposalAttributes.class delete mode 100644 CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/db/ProposalData.class delete mode 100644 CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/test.class delete mode 100644 CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/ArrayDBUtils.class delete mode 100644 CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/Checks.class delete mode 100644 CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/Eventlogs.class delete mode 100644 CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/consts.class delete mode 100644 CPSTreasury/build/libs/CPFTreasury-0.9.1-optimized.jar delete mode 100644 CPSTreasury/build/libs/CPFTreasury-0.9.1.jar delete mode 100644 CPSTreasury/build/libs/CPSTreasury-0.9.1-optimized.jar delete mode 100644 CPSTreasury/build/libs/CPSTreasury-0.9.1.jar delete mode 100644 CPSTreasury/build/libs/irc2-token-0.9.1-optimized.jar delete mode 100644 CPSTreasury/build/libs/irc2-token-0.9.1.jar delete mode 100644 CPSTreasury/build/tmp/jar/MANIFEST.MF delete mode 100644 CPSTreasury/build/tmp/optimizedJar/MANIFEST.MF diff --git a/CPFTreasury/build/classes/java/main/com/iconloop/score/example/test.class b/CPFTreasury/build/classes/java/main/com/iconloop/score/example/test.class deleted file mode 100644 index ed4c75e13a813d58bcfa52a5e746bb1492237377..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1973 zcmah~ZBr9h6n-uw*<@XLi6W)6A`#kP!KiJq2DELcRBS*j6ko8#OL7TIHoM#1jbp~~ zfAnv(AEIMt`UCo-I(=?JAQYs`u=kvE&w0*sUUu{MKkxnma1*|XbGVkK{Dp}GzD!{j zH%)wnTL$vlGN+Y!6Sr~4#Mk&HiL8llQP9dl65~mXnfMNOwcDbB?+x4&NX*-=9o-S= z%}#9y#1_1=66i15u3D+rwpFk$w;fv2MXw~C4H?*4-#5mhT{{#QFP6Mo&MtYb<9U8A zEO~*-sh6_mJ1Q5cFq$K9P1>%&h3sZ=Pri^jN4k~VS`^rBWv-Q21{Fe`JKN#*oS z?miz6w)a#?vrW`gwCgb{)ycdiU>?X?x%;xD{K)p)&;U6NEVm+7H8T~dfb7h*7W|^E z`?bG`9S})9uVmXWH}1evEu^Q&ynZb(T$5F`;JGCkJ+h-+ zN?|13i0vE7E=`>@-(*Eag$CQnnP#W-l)Kx~2qRVFHhcAm5bb!|%dK+JBCeZ~HIBDk z%Tcp{;cF*{OEQ%0O1!@mdP(Ei&4NCU+;=VUsBY|gc8k$$L&)~ecB6NqPg~0k>C_cz zUpfW8<->)SVP{~I*{Rb&4|aY06x0q@FMHksZ_^bxPw>Nq*e^n0@X)s8MyjF$MzzYO z`kub=<%x0B8wPgu?mGe#hbXrD!mFzN4@G-T7G){&f`$PODpB;jYTXyGmRwf_3yuu= zRtx;r-QsZH_^ND2Vyf##Q#L%$;=xV`4|l&u_lruvA0MyVdmo_@${J{ ztR~Lp6O{W}vYGDRw;3bGTMW!5890<|V(^gI4blP5Fqy^FXVHg#)-s4O*7qsvx=!sj z$vwm{9+Uoa($+;hYZJxCxJa#spSv+!VqqzIjUz)#AJ%Xg6D(;A1x(TwBic25Lfkkp zCy=ErLF55UQQ}vW(N~C)#An2e5p5bXl;VPEK%lFwR5?_6n!L7A!yXA;r=FyKga4oZ E3u`<1o&W#< diff --git a/CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/CPFTreasury.class b/CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/CPFTreasury.class deleted file mode 100644 index 621e210a8aff74bd1d52d7f854fdd90d1a083411..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19139 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 diff --git a/CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/utils/ArrayDBUtils.class b/CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/utils/ArrayDBUtils.class deleted file mode 100644 index 509873c1649929bea8b394d576c275204296ff56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3610 zcmbW4TUQfT6vzK3nJ^GXkV{ZRS}I;b495Enj8#O%2D|`TuQ((FMw1Lq5)^x1%P(P{ zT36Td#RvORwOwWPxlipks9(cHZU5)Y1aoU^6_azBea_kYcm8`1{QCOGB>?;JRS*G8 ztimuRWp65o3%ID`V>xq4eqGjaC5T38a}}2xaV?1Jn3jVZI!tLXBL_*@yCHii9aa$S zn3988`85|rGp2Oh6lfSq=hB6^fIr-SK|mX}QAb+fMAFV?i`-{1mQLEaSaLoe%O`EeiVdGVG3i)lzUVB*iiLD0A3N$e z=Hl^VQ*tmUu-dV*_JTE%v9eaKAh0K#xMePw$~cxt=L>`GIAiAKVrOPxKguG z$&sE~M@~3)))NcwBAjpq<;~C~s#V+)(A8}nKPE+6X+m)o^Oln%!D&|ueU%nNWe6t< zPC7TI?q*Zy`bh=<=r_EG~^5Mm9s@kQV;wiR9cWr8h zx+|E@oJHMf`Sg9tL7TRV9IXIwcjhJaRtM}6@(iRB_g0-gR9doPQx<+H0qM@V+KBRs zp{x}ug;mOWTm=r)oKs^I|A)wf6L!%_S|`%75Vd*=Pz7YW+`~W@)*HBm+Xgbo>c|#_~jSf=m@DAuD(_VYFSLs|w(ZB-k8n_3RhO(XA z01ezn*1#vyk^A_R(yJhC;4^$~;0t^yu>T#4r9kr=m!-GVe!*7G3WUP_b*oi_b*E@% z7;eZ*>WVtbYb=jsF;88x&?uoL?Rf?osk3af?0P*xj4F})>{)@$;X01gsULjbuuzvU zxi5v4@vxmMSoatqE9`>huv6i`Cn{M2{3;JZ;ZkKOkB?88WCB4~stHpvtJtWdXSvb5 zP04hGJy)yt$;)i(4A%+0{{nVm9pBXQUjsiBBLuqHi?J1K1CeJC-?QVx27WiFNdrCX z8?FJ~!}}aHp%)*(FBgj=+){2g8+ierz?eVo-=~GN=+Yy^q9JY9wjbbsi1(sPAuXk) z_60bn-QZU!@En>Je~hLFnt1%zZ#`f0{HM|Al9mz^^80554rx(;m&X4~wC&QKqv0t} z(v){`w6MPhI@;(@JAXRpT?kvzi9J}0eGK*>XOGa!VXhdV=Lvc}g+AQCW);;buHMS^ z8#xzXjJvUkJxxYKi!E$rZ!5x#UdJ^05h0rtUb ztgPJ0mAg3G0_`;n9lM2yzCs{CX9?8D^T3mUz5Mv-eG`AjI^Z(KOL`|SZp35U%~luq zRuNn3Cf9hhn^e1d$m#77Zs8%I`#OV>fwW@>HL;Trb~C`e^lU%z9aO0HxDKpf8R2}N z3NG$pSvMa1cW-1u?)@-p$>g z(0J(?n#LrCAm1vf@6gz`>N$*+iEj`gk9f};gZ0r!&kL;f;TJT&K#LC-ANVP|KWMRr zNfqyjDx`9+u1J)ot)6L{56beTObl0gyC@alFn_m=Q*=j|Nk8f zW~VUEb^)hX81|FUVMS?@w4~gmXzp^SBWz{Q<=V(s!-tfhPf5#VD6Njt#(j3o6I3Sx z%jnWEyo?s{3LBRxjaL-9r>i&@ydip=L`UePo4bCtQdd`9PKP5Kw3G*_eSCnK+wl+v zpM?Z2YEM*N)8Y{ZA|b70=URn0Gw=ePeyo_QwEo@yg!`9c8>0lqiR}z?@+`wYM|2Yu z-Xy_I;UoSPaUK^rn!siL$l4>N7iR91a`P&Yy0ESiu$!Axd|CDpNC#(5a~HqD=2k6f zpWr?+`&yy>iOoVs`!cK5HYQ++(@8!(#gD7JF>)Gz8&1uN)7t;!)J#sadV5aSRmJI` yh&I4vY%}DPA}5QSW*OleIo%|u6e-<)M^0yII7xX`aBBW{PG?yH&T)+o=l=%J9~UzK diff --git a/CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/utils/Eventlogs.class b/CPFTreasury/build/classes/java/main/community/icon/cps/score/CPFTreasury/utils/Eventlogs.class deleted file mode 100644 index 48fa99a8fd3599d4ee9014e6179ac21e4844769d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1065 zcmbtS%We}f6g{4#36rKz`r-`|5`hJ?;jsupstS=R4G^_aw~;gBq%IRX*q(@d7Aqtc zd;lMXxXy&45TOXLbS>ZG>vMdr{q6gguK=FoZVe^es^WGPcNi)!q>}C>L#grbjG=s_ zQ^BwiOC{ds!=5l5-pdHtj&;JbGj62MXJFZ#OUv*qPV{h?6VD`)iB?fEvXM=+5z$e* z)iHwG+)Sd}$;?Kt$3nSG4{Vd6-pW;aB3y2iNEz-o;^Nd{ni^qkGrr(s9%Wn&qElz2 z8Z`YKH@kMEmDQ%pi#mVb`GaIcX*a$00tFGg5$;^4ZEpBbIAO@bjgwqCITXigEUhGm zhl&WelO#mDGkSgr7B*r%AQx4sQt?rwC2B8Y*l!y>(w1l5T*q)_`@$IS??GeH&?4e3 zhFv-8+wOZYVc7Y}_e$CiInQKYda_yX5+TPvt)1%JB%&q#W368{`LVZOM;R*&PyXeV zs9V1}_^x*$5{G*T=nMI=0_ya1u22?H#ytAyGuS6u1gO$nnSvEup>@3|K!_S;Ayx?~ zQ3ddnBA{3}7)}rF6`NSYIu%hFHn2(a7Olg8U=RRoQ>+qvm15@@yCkuP{bdqsa}ozc j?8k2s2L$~=;@WbFt^bs`zPwSpa}s~sDEj4OFu=_p_r1#4 diff --git a/CPFTreasury/build/classes/java/test/community/icon/cps/score/CPFTreasury/CPFTTreasuryTest.class b/CPFTreasury/build/classes/java/test/community/icon/cps/score/CPFTreasury/CPFTTreasuryTest.class deleted file mode 100644 index 6deb7e5f097f36109770283ad3af565b9bfa1ee7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21411 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 IdybR;0VAfbtN;K2 diff --git a/CPFTreasury/build/libs/CPFTreasury-0.9.1-optimized.jar b/CPFTreasury/build/libs/CPFTreasury-0.9.1-optimized.jar deleted file mode 100644 index 58bcf6c1468b398110e7a5220133393f2ae460d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28963 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 I)t|rq4}(ae>Hq)$ diff --git a/CPFTreasury/build/libs/CPFTreasury-0.9.1.jar b/CPFTreasury/build/libs/CPFTreasury-0.9.1.jar deleted file mode 100644 index 511c64ea4fdd09dad5ec9ac1726b28f65b94b640..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11843 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 HzrX$;*O!&N diff --git a/CPFTreasury/build/reports/tests/test/classes/community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.html b/CPFTreasury/build/reports/tests/test/classes/community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.html deleted file mode 100644 index a562b8ed..00000000 --- a/CPFTreasury/build/reports/tests/test/classes/community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.html +++ /dev/null @@ -1,879 +0,0 @@ - - - - - -Test results - CPFTTreasuryTest - - - - - -
-

CPFTTreasuryTest

-
-
- - - - - -
-
- - - - - - - -
-
-
23
-

tests

-
-
-
-
0
-

failures

-
-
-
-
0
-

ignored

-
-
-
-
0.535s
-

duration

-
-
-
-
-
-
100%
-

successful

-
-
-
-
- -
-

Tests

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TestDurationResult
addFundExtraBnUSD()0.008spassed
addFundExtraICX()0.007spassed
disqualifyProposalFund()0.049spassed
name()0.001spassed
resetSwapState()0.005spassed
returnFundAmountExtraBnUSD()0.241spassed
returnFundAmountExtraICX()0.017spassed
setBMUSDScore()0.001spassed
setBNUSDScoreNotOwner()0.009spassed
setCPSScore()0.002spassed
setCPSScoreNotOwner()0.048spassed
setCPSTreasuryScore()0.001spassed
setCPSTreasuryScoreNotOwner()0.047spassed
setDEXScore()0.001spassed
setDEXScoreNotOwner()0.008spassed
setMaxCapIcxAndBnusdTest()0.004spassed
setRouterScore()0.001spassed
setRouterScoreNotOwner()0.010spassed
setSICXScore()0.001spassed
setSICXScoreNotOwner()0.009spassed
swapTokens()0.022spassed
transferProposalFundToCPSTreasury()0.025spassed
updateProposalFund()0.018spassed
-
-
-

Standard output

- -
[{_budget_transfer=102000000000000000000, _ipfs_hash=Proposal 1}, {_budget_transfer=112200000000000000000, _ipfs_hash=Proposal 2}, {count=2}]
-[{_budget_transfer=22000000000000000000, _ipfs_hash=Proposal 1}, {_budget_transfer=112200000000000000000, _ipfs_hash=Proposal 2}, {count=2}]
-[{_budget_transfer=102000000000000000000, _ipfs_hash=Proposal 1}, {_budget_transfer=112200000000000000000, _ipfs_hash=Proposal 2}, {count=2}]
-balue2000000000000000000000
-2000000000000000000000
-[Proposal 1]
-null
-
-
-
-
-

Standard error

- -
java.lang.reflect.InvocationTargetException
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at com.iconloop.score.test.Score.call(Score.java:90)
-	at com.iconloop.score.test.Score.invoke(Score.java:62)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setCPSTreasuryScoreExceptions(CPFTTreasuryTest.java:141)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.lambda$setCPSTreasuryScoreNotOwner$1(CPFTTreasuryTest.java:187)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:55)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:37)
-	at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3082)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.expectErrorMessage(CPFTTreasuryTest.java:415)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setCPSTreasuryScoreNotOwner(CPFTTreasuryTest.java:188)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
-	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
-	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
-	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
-	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
-	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
-	at com.sun.proxy.$Proxy2.stop(Unknown Source)
-	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
-	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
-	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
-	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
-	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
-	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
-	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
-	at java.base/java.lang.Thread.run(Thread.java:829)
-Caused by: java.lang.AssertionError: CPF_TREASURY: Only owner can call this method
-	at score.Context.require(Context.java:143)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwner(CPFTreasury.java:77)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwnerScore(CPFTreasury.java:82)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.setCpsTreasuryScore(CPFTreasury.java:155)
-	... 101 more
-java.lang.reflect.InvocationTargetException
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at com.iconloop.score.test.Score.call(Score.java:90)
-	at com.iconloop.score.test.Score.invoke(Score.java:62)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setDEXScoreExceptions(CPFTTreasuryTest.java:165)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.lambda$setDEXScoreNotOwner$4(CPFTTreasuryTest.java:205)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:55)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:37)
-	at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3082)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.expectErrorMessage(CPFTTreasuryTest.java:415)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setDEXScoreNotOwner(CPFTTreasuryTest.java:206)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
-	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
-	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
-	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
-	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
-	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
-	at com.sun.proxy.$Proxy2.stop(Unknown Source)
-	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
-	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
-	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
-	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
-	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
-	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
-	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
-	at java.base/java.lang.Thread.run(Thread.java:829)
-Caused by: java.lang.AssertionError: CPF_TREASURY: Only owner can call this method
-	at score.Context.require(Context.java:143)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwner(CPFTreasury.java:77)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwnerScore(CPFTreasury.java:82)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.setDexScore(CPFTreasury.java:218)
-	... 101 more
-java.lang.reflect.InvocationTargetException
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at com.iconloop.score.test.Score.call(Score.java:90)
-	at com.iconloop.score.test.Score.invoke(Score.java:62)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setBNUSDScoreExceptions(CPFTTreasuryTest.java:149)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.lambda$setBNUSDScoreNotOwner$2(CPFTTreasuryTest.java:193)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:55)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:37)
-	at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3082)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.expectErrorMessage(CPFTTreasuryTest.java:415)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setBNUSDScoreNotOwner(CPFTTreasuryTest.java:194)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
-	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
-	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
-	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
-	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
-	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
-	at com.sun.proxy.$Proxy2.stop(Unknown Source)
-	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
-	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
-	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
-	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
-	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
-	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
-	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
-	at java.base/java.lang.Thread.run(Thread.java:829)
-Caused by: java.lang.AssertionError: CPF_TREASURY: Only owner can call this method
-	at score.Context.require(Context.java:143)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwner(CPFTreasury.java:77)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwnerScore(CPFTreasury.java:82)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.setBnUSDScore(CPFTreasury.java:176)
-	... 101 more
-java.lang.reflect.InvocationTargetException
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at com.iconloop.score.test.Score.call(Score.java:90)
-	at com.iconloop.score.test.Score.invoke(Score.java:62)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setRouterScoreExceptions(CPFTTreasuryTest.java:173)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.lambda$setRouterScoreNotOwner$5(CPFTTreasuryTest.java:211)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:55)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:37)
-	at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3082)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.expectErrorMessage(CPFTTreasuryTest.java:415)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setRouterScoreNotOwner(CPFTTreasuryTest.java:212)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
-	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
-	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
-	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
-	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
-	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
-	at com.sun.proxy.$Proxy2.stop(Unknown Source)
-	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
-	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
-	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
-	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
-	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
-	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
-	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
-	at java.base/java.lang.Thread.run(Thread.java:829)
-Caused by: java.lang.AssertionError: CPF_TREASURY: Only owner can call this method
-	at score.Context.require(Context.java:143)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwner(CPFTreasury.java:77)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwnerScore(CPFTreasury.java:82)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.setRouterScore(CPFTreasury.java:239)
-	... 101 more
-java.lang.reflect.InvocationTargetException
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at com.iconloop.score.test.Score.call(Score.java:90)
-	at com.iconloop.score.test.Score.invoke(Score.java:62)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setCPSScoreExceptions(CPFTTreasuryTest.java:133)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.lambda$setCPSScoreNotOwner$0(CPFTTreasuryTest.java:181)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:55)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:37)
-	at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3082)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.expectErrorMessage(CPFTTreasuryTest.java:415)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setCPSScoreNotOwner(CPFTTreasuryTest.java:182)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
-	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
-	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
-	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
-	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
-	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
-	at com.sun.proxy.$Proxy2.stop(Unknown Source)
-	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
-	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
-	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
-	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
-	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
-	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
-	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
-	at java.base/java.lang.Thread.run(Thread.java:829)
-Caused by: java.lang.AssertionError: CPF_TREASURY: Only owner can call this method
-	at score.Context.require(Context.java:143)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwner(CPFTreasury.java:77)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwnerScore(CPFTreasury.java:82)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.setCpsScore(CPFTreasury.java:134)
-	... 101 more
-java.lang.reflect.InvocationTargetException
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at com.iconloop.score.test.Score.call(Score.java:90)
-	at com.iconloop.score.test.Score.invoke(Score.java:62)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setSICXScoreExceptions(CPFTTreasuryTest.java:157)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.lambda$setSICXScoreNotOwner$3(CPFTTreasuryTest.java:199)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:55)
-	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:37)
-	at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3082)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.expectErrorMessage(CPFTTreasuryTest.java:415)
-	at community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.setSICXScoreNotOwner(CPFTTreasuryTest.java:200)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
-	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
-	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
-	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
-	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
-	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
-	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
-	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
-	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
-	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
-	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
-	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
-	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
-	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
-	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
-	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
-	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
-	at com.sun.proxy.$Proxy2.stop(Unknown Source)
-	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
-	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
-	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
-	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
-	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
-	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
-	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
-	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
-	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
-	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
-	at java.base/java.lang.Thread.run(Thread.java:829)
-Caused by: java.lang.AssertionError: CPF_TREASURY: Only owner can call this method
-	at score.Context.require(Context.java:143)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwner(CPFTreasury.java:77)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.validateOwnerScore(CPFTreasury.java:82)
-	at community.icon.cps.score.CPFTreasury.CPFTreasury.setSicxScore(CPFTreasury.java:197)
-	... 101 more
-
-
-
-
- -
- - diff --git a/CPFTreasury/build/reports/tests/test/css/base-style.css b/CPFTreasury/build/reports/tests/test/css/base-style.css deleted file mode 100644 index 4afa73e3..00000000 --- a/CPFTreasury/build/reports/tests/test/css/base-style.css +++ /dev/null @@ -1,179 +0,0 @@ - -body { - margin: 0; - padding: 0; - font-family: sans-serif; - font-size: 12pt; -} - -body, a, a:visited { - color: #303030; -} - -#content { - padding-left: 50px; - padding-right: 50px; - padding-top: 30px; - padding-bottom: 30px; -} - -#content h1 { - font-size: 160%; - margin-bottom: 10px; -} - -#footer { - margin-top: 100px; - font-size: 80%; - white-space: nowrap; -} - -#footer, #footer a { - color: #a0a0a0; -} - -#line-wrapping-toggle { - vertical-align: middle; -} - -#label-for-line-wrapping-toggle { - vertical-align: middle; -} - -ul { - margin-left: 0; -} - -h1, h2, h3 { - white-space: nowrap; -} - -h2 { - font-size: 120%; -} - -ul.tabLinks { - padding-left: 0; - padding-top: 10px; - padding-bottom: 10px; - overflow: auto; - min-width: 800px; - width: auto !important; - width: 800px; -} - -ul.tabLinks li { - float: left; - height: 100%; - list-style: none; - padding-left: 10px; - padding-right: 10px; - padding-top: 5px; - padding-bottom: 5px; - margin-bottom: 0; - -moz-border-radius: 7px; - border-radius: 7px; - margin-right: 25px; - border: solid 1px #d4d4d4; - background-color: #f0f0f0; -} - -ul.tabLinks li:hover { - background-color: #fafafa; -} - -ul.tabLinks li.selected { - background-color: #c5f0f5; - border-color: #c5f0f5; -} - -ul.tabLinks a { - font-size: 120%; - display: block; - outline: none; - text-decoration: none; - margin: 0; - padding: 0; -} - -ul.tabLinks li h2 { - margin: 0; - padding: 0; -} - -div.tab { -} - -div.selected { - display: block; -} - -div.deselected { - display: none; -} - -div.tab table { - min-width: 350px; - width: auto !important; - width: 350px; - border-collapse: collapse; -} - -div.tab th, div.tab table { - border-bottom: solid #d0d0d0 1px; -} - -div.tab th { - text-align: left; - white-space: nowrap; - padding-left: 6em; -} - -div.tab th:first-child { - padding-left: 0; -} - -div.tab td { - white-space: nowrap; - padding-left: 6em; - padding-top: 5px; - padding-bottom: 5px; -} - -div.tab td:first-child { - padding-left: 0; -} - -div.tab td.numeric, div.tab th.numeric { - text-align: right; -} - -span.code { - display: inline-block; - margin-top: 0em; - margin-bottom: 1em; -} - -span.code pre { - font-size: 11pt; - padding-top: 10px; - padding-bottom: 10px; - padding-left: 10px; - padding-right: 10px; - margin: 0; - background-color: #f7f7f7; - border: solid 1px #d0d0d0; - min-width: 700px; - width: auto !important; - width: 700px; -} - -span.wrapped pre { - word-wrap: break-word; - white-space: pre-wrap; - word-break: break-all; -} - -label.hidden { - display: none; -} \ No newline at end of file diff --git a/CPFTreasury/build/reports/tests/test/css/style.css b/CPFTreasury/build/reports/tests/test/css/style.css deleted file mode 100644 index 3dc4913e..00000000 --- a/CPFTreasury/build/reports/tests/test/css/style.css +++ /dev/null @@ -1,84 +0,0 @@ - -#summary { - margin-top: 30px; - margin-bottom: 40px; -} - -#summary table { - border-collapse: collapse; -} - -#summary td { - vertical-align: top; -} - -.breadcrumbs, .breadcrumbs a { - color: #606060; -} - -.infoBox { - width: 110px; - padding-top: 15px; - padding-bottom: 15px; - text-align: center; -} - -.infoBox p { - margin: 0; -} - -.counter, .percent { - font-size: 120%; - font-weight: bold; - margin-bottom: 8px; -} - -#duration { - width: 125px; -} - -#successRate, .summaryGroup { - border: solid 2px #d0d0d0; - -moz-border-radius: 10px; - border-radius: 10px; -} - -#successRate { - width: 140px; - margin-left: 35px; -} - -#successRate .percent { - font-size: 180%; -} - -.success, .success a { - color: #008000; -} - -div.success, #successRate.success { - background-color: #bbd9bb; - border-color: #008000; -} - -.failures, .failures a { - color: #b60808; -} - -.skipped, .skipped a { - color: #c09853; -} - -div.failures, #successRate.failures { - background-color: #ecdada; - border-color: #b60808; -} - -ul.linkList { - padding-left: 0; -} - -ul.linkList li { - list-style: none; - margin-bottom: 5px; -} diff --git a/CPFTreasury/build/reports/tests/test/index.html b/CPFTreasury/build/reports/tests/test/index.html deleted file mode 100644 index 43e5d4a4..00000000 --- a/CPFTreasury/build/reports/tests/test/index.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - - -Test results - Test Summary - - - - - -
-

Test Summary

-
- - - - - -
-
- - - - - - - -
-
-
23
-

tests

-
-
-
-
0
-

failures

-
-
-
-
0
-

ignored

-
-
-
-
0.535s
-

duration

-
-
-
-
-
-
100%
-

successful

-
-
-
-
- -
-

Packages

- - - - - - - - - - - - - - - - - - - - - -
PackageTestsFailuresIgnoredDurationSuccess rate
-community.icon.cps.score.CPFTreasury -23000.535s100%
-
-
-

Classes

- - - - - - - - - - - - - - - - - - - - - -
ClassTestsFailuresIgnoredDurationSuccess rate
-community.icon.cps.score.CPFTreasury.CPFTTreasuryTest -23000.535s100%
-
-
- -
- - diff --git a/CPFTreasury/build/reports/tests/test/js/report.js b/CPFTreasury/build/reports/tests/test/js/report.js deleted file mode 100644 index 83bab4a1..00000000 --- a/CPFTreasury/build/reports/tests/test/js/report.js +++ /dev/null @@ -1,194 +0,0 @@ -(function (window, document) { - "use strict"; - - var tabs = {}; - - function changeElementClass(element, classValue) { - if (element.getAttribute("className")) { - element.setAttribute("className", classValue); - } else { - element.setAttribute("class", classValue); - } - } - - function getClassAttribute(element) { - if (element.getAttribute("className")) { - return element.getAttribute("className"); - } else { - return element.getAttribute("class"); - } - } - - function addClass(element, classValue) { - changeElementClass(element, getClassAttribute(element) + " " + classValue); - } - - function removeClass(element, classValue) { - changeElementClass(element, getClassAttribute(element).replace(classValue, "")); - } - - function initTabs() { - var container = document.getElementById("tabs"); - - tabs.tabs = findTabs(container); - tabs.titles = findTitles(tabs.tabs); - tabs.headers = findHeaders(container); - tabs.select = select; - tabs.deselectAll = deselectAll; - tabs.select(0); - - return true; - } - - function getCheckBox() { - return document.getElementById("line-wrapping-toggle"); - } - - function getLabelForCheckBox() { - return document.getElementById("label-for-line-wrapping-toggle"); - } - - function findCodeBlocks() { - var spans = document.getElementById("tabs").getElementsByTagName("span"); - var codeBlocks = []; - for (var i = 0; i < spans.length; ++i) { - if (spans[i].className.indexOf("code") >= 0) { - codeBlocks.push(spans[i]); - } - } - return codeBlocks; - } - - function forAllCodeBlocks(operation) { - var codeBlocks = findCodeBlocks(); - - for (var i = 0; i < codeBlocks.length; ++i) { - operation(codeBlocks[i], "wrapped"); - } - } - - function toggleLineWrapping() { - var checkBox = getCheckBox(); - - if (checkBox.checked) { - forAllCodeBlocks(addClass); - } else { - forAllCodeBlocks(removeClass); - } - } - - function initControls() { - if (findCodeBlocks().length > 0) { - var checkBox = getCheckBox(); - var label = getLabelForCheckBox(); - - checkBox.onclick = toggleLineWrapping; - checkBox.checked = false; - - removeClass(label, "hidden"); - } - } - - function switchTab() { - var id = this.id.substr(1); - - for (var i = 0; i < tabs.tabs.length; i++) { - if (tabs.tabs[i].id === id) { - tabs.select(i); - break; - } - } - - return false; - } - - function select(i) { - this.deselectAll(); - - changeElementClass(this.tabs[i], "tab selected"); - changeElementClass(this.headers[i], "selected"); - - while (this.headers[i].firstChild) { - this.headers[i].removeChild(this.headers[i].firstChild); - } - - var h2 = document.createElement("H2"); - - h2.appendChild(document.createTextNode(this.titles[i])); - this.headers[i].appendChild(h2); - } - - function deselectAll() { - for (var i = 0; i < this.tabs.length; i++) { - changeElementClass(this.tabs[i], "tab deselected"); - changeElementClass(this.headers[i], "deselected"); - - while (this.headers[i].firstChild) { - this.headers[i].removeChild(this.headers[i].firstChild); - } - - var a = document.createElement("A"); - - a.setAttribute("id", "ltab" + i); - a.setAttribute("href", "#tab" + i); - a.onclick = switchTab; - a.appendChild(document.createTextNode(this.titles[i])); - - this.headers[i].appendChild(a); - } - } - - function findTabs(container) { - return findChildElements(container, "DIV", "tab"); - } - - function findHeaders(container) { - var owner = findChildElements(container, "UL", "tabLinks"); - return findChildElements(owner[0], "LI", null); - } - - function findTitles(tabs) { - var titles = []; - - for (var i = 0; i < tabs.length; i++) { - var tab = tabs[i]; - var header = findChildElements(tab, "H2", null)[0]; - - header.parentNode.removeChild(header); - - if (header.innerText) { - titles.push(header.innerText); - } else { - titles.push(header.textContent); - } - } - - return titles; - } - - function findChildElements(container, name, targetClass) { - var elements = []; - var children = container.childNodes; - - for (var i = 0; i < children.length; i++) { - var child = children.item(i); - - if (child.nodeType === 1 && child.nodeName === name) { - if (targetClass && child.className.indexOf(targetClass) < 0) { - continue; - } - - elements.push(child); - } - } - - return elements; - } - - // Entry point. - - window.onload = function() { - initTabs(); - initControls(); - }; -} (window, window.document)); \ No newline at end of file diff --git a/CPFTreasury/build/reports/tests/test/packages/community.icon.cps.score.CPFTreasury.html b/CPFTreasury/build/reports/tests/test/packages/community.icon.cps.score.CPFTreasury.html deleted file mode 100644 index d2560ae4..00000000 --- a/CPFTreasury/build/reports/tests/test/packages/community.icon.cps.score.CPFTreasury.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - -Test results - Package community.icon.cps.score.CPFTreasury - - - - - -
-

Package community.icon.cps.score.CPFTreasury

- -
- - - - - -
-
- - - - - - - -
-
-
23
-

tests

-
-
-
-
0
-

failures

-
-
-
-
0
-

ignored

-
-
-
-
0.535s
-

duration

-
-
-
-
-
-
100%
-

successful

-
-
-
-
- -
-

Classes

- - - - - - - - - - - - - - - - - - - -
ClassTestsFailuresIgnoredDurationSuccess rate
-CPFTTreasuryTest -23000.535s100%
-
-
- -
- - diff --git a/CPFTreasury/build/test-results/test/TEST-community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.xml b/CPFTreasury/build/test-results/test/TEST-community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.xml deleted file mode 100644 index 075eeac5..00000000 --- a/CPFTreasury/build/test-results/test/TEST-community.icon.cps.score.CPFTreasury.CPFTTreasuryTest.xml +++ /dev/null @@ -1,684 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CPFTreasury/build/test-results/test/binary/output.bin b/CPFTreasury/build/test-results/test/binary/output.bin deleted file mode 100644 index 115cd9fcc0c2badd091d0ab00ee56701b3287dab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67481 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 diff --git a/CPFTreasury/build/test-results/test/binary/output.bin.idx b/CPFTreasury/build/test-results/test/binary/output.bin.idx deleted file mode 100644 index 3391fa352f081e6bb646787f4ac4338ee4c580bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 333 zcmZQ%;$r!a1{hF)_8e9SUwa*d)^S8r|DO#iaT!LVE8v7k=%zvGHgpAC=mJoM3n6r* zEFX3Sk@^q?Et>_PjH6Kc8oCA{bOETs`w)6Vx)^o^8!90RZhw`)uHX(kSOFt@I{>4h BvC04d diff --git a/CPFTreasury/build/test-results/test/binary/results.bin b/CPFTreasury/build/test-results/test/binary/results.bin deleted file mode 100644 index 40e6c85ab5895cf21c31de4d015aa8516e9a62c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1328 zcma)6%W4!s6g`vIB=HdwH8CIvqENLN^%F9a1hPmR?D4TJx+^f4scx&P$;{4$APPQ4 ze1)KHbm!VXaO+ACT1$a-j$v2(V~bUordIR9s!VlbcsDn$G(h zjzumLUF`WFLUNbiar~iRE#uUF(##K>coy}tQHzfzG#94KpE&u}FsoZ;iE=K7;h3@g z{lVP6(QdMKjRhNSdqsFv5h^cQV?sxyFkvhF#i@^Gg@xMYGJC5HKeKFv9)*MDxMpt( z^DnX+Ze~E}VFYE%pTokQ>EebTYA$ml7@EMWRiDS{?x5Q2O&&<5-MfG@(cNd7vs+n= zrn-wb``qZNo5?K^nvYZNWh~lixn_z{T(zCt#?pS_1JfVih!o~+g$~ZWF)q`sJ9r?5 Kz{w`{9^gM+!^w~U diff --git a/CPFTreasury/build/tmp/jar/MANIFEST.MF b/CPFTreasury/build/tmp/jar/MANIFEST.MF deleted file mode 100644 index 58630c02..00000000 --- a/CPFTreasury/build/tmp/jar/MANIFEST.MF +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 - diff --git a/CPFTreasury/build/tmp/optimizedJar/MANIFEST.MF b/CPFTreasury/build/tmp/optimizedJar/MANIFEST.MF deleted file mode 100644 index 79c4b8db..00000000 --- a/CPFTreasury/build/tmp/optimizedJar/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: community.icon.cps.score.CPFTreasury.CPFTreasury - diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/CPSTreasury.class deleted file mode 100644 index dff782e2fe56f4d7d1ae3c0136713a57c1607278..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21733 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 diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData$ProposalAttributes.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData$ProposalAttributes.class deleted file mode 100644 index 5865de269c44a2f20d500949eff183ec83079747..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 712 zcmbtS%Wl*#6g{5lyh3QFQz(xD1&IZ8ftM_J35pOSjS5mxx1*cHWLz?KWIMobv8vQX zKcF9lxXEPb7Kx3|eVlWzeXlQnpI-oYj)xJtxHrK40Uij9botfK7vvWLli4YKCs~lm z<#BM@pBkRhFwDu)C5jDJu}9s-Lth3njBeu1mb9K#$kXRXu)lbZje^st>xp&i0y8^PklN78o8W zA3jx?0_*q~4dn!M~TpBXsyz07LL((PN7TjzNP%j2etuyw>L9 z7O%Is*&;6mW7co8N-_$@-oY8fFE%=u@Y!#I5q8*)R|MR^E%v&&-LUT9Zi9Q+WsI29 J!5(g6^aldQw3z?^ diff --git a/CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData.class b/CPSTreasury/build/classes/java/main/com/iconloop/score/example/db/ProposalData.class deleted file mode 100644 index bb0a590060d20a324ec764f6ef61d66588b952cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4198 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 diff --git a/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/CPSTreasury.class b/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/CPSTreasury.class deleted file mode 100644 index 03c5cab8610ae09664e1c648fad9937266bc4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21833 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 SgS#~zV4pE!O$!IOiNPODJ-_7u diff --git a/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/db/ProposalData.class b/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/db/ProposalData.class deleted file mode 100644 index 1529ef0edc6e243660e159f7a898c36b4de8e5ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4258 zcmb_fYkM0<6@Ev)Xk~3|dE#5rG^8|56g!P_Z9`<7SiZClPMpLcAuU9#rM11Ov}<-( zal)-oD813rQlLP&6bMkttyN2F7s|s2KJf4l`VaWZAK>Af)$Cf5Z76xrhuL$PIcMfv z-WmPn%Im;B_{>(A zz21TSSZ4MHvp1RgYyx}mIi^0(!xwn?A`g%9@FgC;%#$Bu>MKlrHIA>v@uY^QG(63F zcqWdoC-FF*)$m*#-_Y>9h8N=ariK?;{jE5@&5pmL;Ux{<)$lzH-`DW6h97A7p@!4E z_D3D~F<#MdK8~Nn@zXedCLqtb&XVI9rBUB^t+|SCdII{CZJX{`$?!a8HEU_!d(iL} z1ya*q!Ewz@&Nb}9;&?7AkeIa=Y{Rd(rocp#dU*Ppaoxz240|CnOZM%BteSDjaL02S zs7JCRWHaeIzER3miVLPMFm+p2%Z9(0$yp0iwr?(&F4<+vTf8O5_8j+uxoo&afvzRj zxn>sp@rrBsmSYP{-j=uEh>fl~m8;QW(KS7aWA1;oT#L0@uMQv!j$O-?<3^U-eCH99 z_TIT{`HMx@SRO4q6`MlWtM+iYN#5m}Wy7*5A>quvC@@Wmlx2IAj8fUO{jr)=8O`M& zDq%a#@+)-A_F*#Yj|jA+_gxZb9dn9Q8eP+tZJw=^=S=saF;^mqoOTLEi3-7DUI|0QH(hYbIip}Mx#qlegQK;sm8c!hnEs+uJZHE@ z+4N19ocB`8Z~!JtHBrU4N|`gp5{2*hf1kBM(++ZHX~Tt*N_@wx zQ*jICq{V6Oj&?!2I>3jZ{yuAZ{uz^t!P9X8vpPm_GLBn1evV&|zLx3$By>E5t2%y( zS9RoYQpa=nm5yUlg~4C9#`XdooXtGd>EzO6V!h<1=`g2& zx0=(eYRce3Q6hp;k1xXBjiwX&^ws*fsVJx?#gst&x>2f_GxIbpJymZ!ysZem<_Ron z_w!~z(NGU$x%Hum3o}$F4Xr`NO6W7=j+^sFr9>NUqdS9pCA-1K>)@#I$M5Ej870Ja0L%hU}&*;jlM1PJz7O<|0-Hy z_zPNx-a^|d+GB)~@p_@Ago%1#hY}|1h58D%D0yeSylVw1CGW16%QgAdNM1#cn%ld9 ztS^$$cEg?Z*9*g)4b%(kcD8L3`SyDG9cl|Z>V#vf*kFtUNo~A{nV$f=ma?_XW%2aC>9YEOPdG^wPLG0tf*djL{WY6sG|Di zL1k}19#Ygcd0bi9!3`yX$ebV)2YS#!E!BfQ>_k7c)&LG;8^vckCUFO0fgc5Ph3CvE#UHNJ%N5ZTU=^QkN5lA`Y$Kb1z;kT5uyM!1T^IMT(!eU#T-?V48xL(f zVyM56u{19ks@>iJgSD%U1;auhWASDhjfCFkqX{AHK!tpAz_rZnU!Y}9WXjMFLKQ_* z;>mm&s@M;c)K5dDg}*x(?rXu*sm^>OQnO7ZA}(WwrS4&H%0F^{!sD?&G+M^v?Lq?A zVW2EHxscy{aj3cFJ){ z5}Esm(jPj{srt) z;cn7dFF*$#-MumZbC@Tqfd#ZsEt206S(UI>yAt#-P~H0sYvTg78BZG)`I{7#FK3Q& s=L^o&G7s0#CV!PYi?~j89C|xgBHkN>TZAm*Cf#a`LP6#&IxD#S6H^Yk!2kdN diff --git a/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/ArrayDBUtils.class b/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/ArrayDBUtils.class deleted file mode 100644 index f68852101c5f0fed813c6c9aa5cbfccff113f2ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3610 zcmbW4TUQfT6vzK3nJ^GXP#`EGEfp^z2IKt(#wwy>gSUXzD-Owk(IkVD1jXLh@=MsK z*44Fq@xi`SZC6=+?o;~>>ep~l+y6N;!Q9$f#pGOOpL6#9o&VkgzrOx)5x_ot6+{5Z z6&S&U>`ex70T*?AEN3psugf~F1ko&QuHtett_5)&Q*v-ahbb+lWb)SOQf}IECd}z9XWA2X%FJFc zos1lNlUng+rXX-2k+O5S68Bk%Wm0xNmYOTX3Mt#MVk2jh6OLsTO3p&8RLo=xu_KOS zE*v{LDF;IWD;+Cm&s(EeD`(}40=vVBTjso}jAMyRp*ZA@vu1uac4qpPl`0Mm)S3u1 z=S#V9?voY}WBgyiKCO5H|f zM|$fWIqujwPb|EPaKaUoH$#`GR&h%}SGRTSs1$9r3B^?^SWcbLRQ_9(?Owr0sndvm;!;9Tmvr8kzQ*6!d+VnJa zS2Ueji@MVanfsK3Hf5JMS_a_m%uDL44cH^(8Av7WsX2YPykyy?BK&d!(w(*S5fv0e zSu0cutCaP)3hb{tr_Lz;50M9xcF9Ru$1}1Jt@ae43dlCOhkn>lRdtltSQ*Jefx2X&Q9?`Ea||@nVA)v3^?HIBQzG}-GXk5!4IF7uKlr|3p)O-` zUkc0P5j$VB?lD4E*m=ugr^vw1?<3DzNzKECVnVJ2=uTQV=LGOBF`YcXUB*2{BBZ{271{y zTm!s^_c>}oA3lIzE*6KmrQB{N@&Z1Aaev&uR|{#;#Yc!mL)y-*KfwPG??o3wT3So* z4RB7o!LLx@IW#T)7%dMp@%XRbdcWrRPovRAEiIDr`)33WYEgf;#{Y}7?be>7=_yar zly`BovA+sB+UZXRe>&-12wTvF-B^RY4E6wL57WyLt{A1~33@$=e%!z&71c?u-oo`8 zI2T}yyReZxO-4hD&1_|F3&MofhPfb`0>&E7XFU4-(`%K^iE#fsK>a6tuFAb zBDUB=uJLFOsrK}e)7vB5%tJu;bp|5?>A-esVh17YVt{+-**@Yspiu309azRP%K3g3 zT-?L5j%y@HKi5@a>0&r^ohv049n!uGqZwie9fVOy;Q-BC3J2-n5Qbd}Vvw!8o4Y@u z`O-7Aj7tnbzE#rSp}Bp!Oj~7g*`TFKB&%HXklN@Kbhw&|(#n zD&8AaNabGLktj`9d#3F^D9e{JFGTMWvrRDC^Eg47 zox~j5d7N5iI6y*&6r~B$l5&%xxyzjnvz0xUYcpRBA5wxoB`uesv^qi?_t{ZTP+bTt zpC+`kgrI3;kJ*v>E~&ocaTM3i?jx94F diff --git a/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/Checks.class b/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/Checks.class deleted file mode 100644 index 1997e2392d6b62e2a275e3468ab08a4597ecf0be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 329 zcmb7<&q~8U5XQer^G9Q}#W(P#J-CPm4~mz7r%;8K-Z$&gZcVbXn-%(4o&*m*fDa{| zRA0au_?Yhp^D*=N^Z5nf29q2k9A`MmFeapTrZfFLVRU}6B*dkC)`W3oIz0<*t=&S_ z4U^N#D%mWhGlTzwalba6a9t_ewt;iD!YJDb_3DLJ)@e~b%@EFh9#D z!3TeUKT15a8)_wmf?YVnIp3Vy_s#zL{o^Nq*Ld7Q6%QJC*uW!(`WvaFd&^KA?2Q>} zhdL1qy-+IgG0!H#obX9X$Y!Wxo{qVZK3;+~cP1^vt1#ACmQ$ZaAY-k9cxD3|Ya@cg zQFLMix4Bsaxs$04-pz$_sh-*)Lw{uSOk18t`6QFhiG<Ck)ZpJ;=T0m(Y?^|xo6iw4QmW9{^ub`jK2bXnw*Q+ z;R!1Am-ufDBxG^cDGDfJ9^L;A_Klnh8g$kRu#R=|J7ofzXi?Nen~*AH058cZWGjX1 zMd5aNiCgGW5~ZPs4LbYeH!B2#0AQ1>P4I29J4e`}5!=^~Xy0(e&h;a@Hym*n_m)CE dBZ^+-6`}f<6fWgKArC$MmC`WWr#2Pr{sDhfz@7jA diff --git a/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/consts.class b/CPSTreasury/build/classes/java/main/community/icon/cps/score/CPSTreasury/utils/consts.class deleted file mode 100644 index fe22216ae5c6fd4a0f3e642d5fe985495d77588c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5507 zcmb7|cVOGb6~^yu4M?VBYejbAIJPr9l9+Lv(bi5fU?rz0#4UGjW@wX`Akq?wRhL?!9N)?*M{$l9E5_KSccAy?giWd+&~*@3{N6+Zkh5 z@+$^ehJCdc&*I+T%9>RQeQ^74$8(<&uXIIiVv-Bdx#9X6~b_HisH zmyuCUHdU?EU2Zf^u5NpCStImaZ*H%|zKay5HB&7e==e$Odz_7!x?D0;GF@Wdhi6{a z_E$=I%gAZEBC#KEw$_x(mZ=?9N{R7@oQ-3rWzCQahDF_fga~R0QRRXaB`&cab2c2y zVdWK5Rttv2e!|(Bj;$mYvCLgjL}gmlDn=(uD<1i2>S~nblEi)nkqWY5cEbOhvrMj{ z>q;rH`~nUoMm~wI68jUZN#RoKpE;XMt#KB*Qr2`6tNumgUli>lvA=TGFX!_j zO^N*tEtiCr*xwNuv~2P}ph`(OB2u6u68k3-hB4}FbEXUd|AjhtEvi|7>EGD!vYAjj z8u|}v7;hMfE6C>Vt^&d!IIf5>Vop<82mho2^M@*iS;Tr0AK`5M3bO^B%nEcHUEZ~+@?+^x zT!3^4*U{2mSGt9mz+OAcEi2m@=*YZMnu*Q?pF|PMN=Yu5Ggha8`Fb>SlGp~$dT?H4 ziJ!??Z*)OQ{45wn7f5^~$|IgEU6Bo~B=NIF^GD|nqni*YUR~nnh=D1DRpGT+9G6^9 zDMOeooNdCvSBsUR72kMPT8ikZgVM_!#FCt?R&%&Iu18+8Ud6~u>;`m!QPxU^rW?rU zh^*(K?N(f+9c$Wy=OSoME19}FRWUWvoae#&h-x0p>++GVBIo1mCm~i0UVv58i!Kpy z8|s}*Svk5LO@hk~cTqvKNBqqr@g1mII!WZ8jO@fNqwfNVUx;RnPc@BDmQ^(JMVxJn z$D&hct@OAUw=19NS4Qm=JPWmwyrwjKOC_@|K_U0Ko*Q0`a%|r*jmF3|YYsFl zxSmsLH)b8*v}fzEj24}vqVIcc_PA3G#fw3!Rd=g)=r+C0Wyg1$ zHQbrg%@A(`T^=!g+Y8(!KEqbcZXRoUH7nXNf?J{8vcl#G$4g8TR?Ba;nt@#pEb2NW z_V3ztYqs93o`CFDD_YsAIiU@)AV$aF*$qfD-twIVx7iL7zu25O1ufgd1zfj-Fo`%+ zZTr6Cb$QTpPIY0}cN#WQ@aC-074gT~t(qM=Np#n%Ij7JfcCF!hNMZ2Z${~IyI{^J{&8O8irzzXgr$Hap)QbM3wMP z+-N}@_51?|~}8?F>`1j$9mWl5z|TchcP$af^^k=pTg z5H_#?uHO|l3tJD{kaB5Dr2;1QKC4UDr0;$pntva406h0P8JEnJIDA6_SI zABwI`4BhIE;abFRli79%x2|>VNjIFY`S!_fhLg$66(j4?tr#OWHH;st(*9d z-_s9FXpAeT?P$k1+pzu6j(htRDmB{m&~4RmM0RbzXQz9a%eLS*Zw5a)AHp_>?azC+X?Rg?<9O7_#(m=gLe_mf-fPw8+<9@J>bg-Uk<*4@Ri{E5WX+?euVde_YuAd zd^O=~!1pICgQp1RzhGFei8V^gkJ)FDdCraUrzWH;8zlU75LSJ zUju$E;n#s*Pxw0U8wkG$jo_OI zp9a61@O!{F6TSs}E8+KoZzKFZ@cRjW0DL>)4}w2L_`~3j5dJ9mV}w5r{siGqfJf1VL1N#E|B1mFi>Q0`5xA?bp yoUOW*^_*tCBB=$iOnMaX_nfO0Ti4EWwt!DwOUk0yYU-=(z_T+8= diff --git a/CPSTreasury/build/libs/CPFTreasury-0.9.1-optimized.jar b/CPSTreasury/build/libs/CPFTreasury-0.9.1-optimized.jar deleted file mode 100644 index ad18bcde5eb26bbc4ac2605f652988f60f5db149..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28669 zcmagFV~}lYx22o5ZQHhO+qP}nwr$(CZDXai(knCX+NW;Ssn`*9z8Nw8%^7cu(VyAT zS|1A1z#u395D*Xm004x4umAp_0KfvsimC|GO3I1R%L>X#iis+#(8-Fas(=Cj{`0l( zDFA>c*_mk>Xr1*O&{67zd1%UkTg9Q~NmH*F)wQ0L{NP-w)>7}F8i^_BW#zxC5mO+t?UMGVl z2H~zI?rypGH12?|!<}VBYf2Wu8t^f_u*mdd_Gain6Exln$WqOBJWqc8)B5L!1DJee zF;nDm-f20^I7!(b+B<`*0L=YfM4YC6v%S(`Mc8ab23Ny-1Mj2}B7}UUg;0qnAkd@T z6{Q*B7Edd*&&hq)06le8Y?rzF6EOA`F#WCHIao4jGhWwBU9e zh)~Thu1lt-^pau_hgFiiVx}?h_Mi7w^=OdlKyuf(-*rqM5P}GmxTMTGXE%bZ<^;0dfKf zUCN(gi&AdrBy*1)&orY!{)HH6NicQrTdBGu1ZW_M$<`|{!jGEn`%b-#I(?-w!3!L# zURy6c)}UFnI^(KWiBdKku%!l4L@?g z+p%XFsH|URET8;gHx?B-k9Gh&I<53wU>0eCq{X=&(mnh?#M^Qbi_`%D04PKLPsD@& zC0>fo*v8P=`M+7$gf>7~UF9=xik~ziV8{lr_NaMCHAxPD2N@QIK!6Mj01;G(Ouix`@%)QI;K7Wr7%L53|Tv7tjIRh8LXqVhBl8v{H+`FLeV!PN4!z7KY9p4wdd@Itd$AlFyO?dAZJWQT!GyP7aY|wr zNt`0~Y|EK@*-;l?Vs5nSW(urMCb1Y(XiK(zc4_Y5n?#c#X9mlgTg{hRtxRKFopxEm z2&S4hmx_K))t$TY%A}K~LTm3?1)8&V=CJT<&6d_a(bdGT~g0f-4XZsrTyS~R0P)M|J_8wS}Ri(M6 z?Ov@>4IP{SG(K`O6RB6{5QlButZ%^nza18N(n0o3Bt9LQJ5TK2c{k5fUKi+2b?>yNo>RA1cm2}Ep_1& zbSpdrsFtjxUqbEH)V-pj61Or0$bE448upc7h7tgdg_iChaS?fuK|IlcO&FOgafxC$ zT}2?z3+i3ZJim>0E&b-o1sp#L?3yQ3H@wnV>!FdzfpWo!?vnZ%Vr3mJ1WE^bopA`S zC{52C`jBmX8CL<7V;ZF`yz4jGwa{YlxEtx*jYbZ3%M1>SfNk$B+oSpIO_V)UOXgR2 zMJs!MDo_lDVYnn{TJ~;!L7AR9e(a&!?nai3J)CmUD(d>@kT(0+kypmEF@SN0>!N3@ zp*OB!%Aq-gIhu0&z*02l5xq*&DE*|HrEhfJ9K0CZtq-Q(Y}L=IsLj)3#RkqRU8#KWg+PFJ-3lz)=X13P(OR|H2%z`8S^MIVL!n|42+k52!CS$ zKe0zB|HQqz5VWa%vQ<=^C-k0~{}*=QdMh6PpJ1nW647s0(4kF#^<;Z7&~L~es$lnn zeU$jx6gSa$m^(t6S^eKXps9Dws(b`<$aLkemW?6zzH@r5d~*7bgd^_JEh#Ygh#=Q| z)ycRkl4R6DIg@UhhfR$b?r4lmQW`>=5MC5i<*va7_DPm@w`+*eygOUbj_pA15Z|I| zoV5l5Bi=O5xPvm7emKYjjXALnLCs-LJfP!@SZxO$A<5iICm4f;S;c$_)R+2^T$btK4$n`79Fi9*o?gznfv60Uo)JRfU%hPNGE zPnZ+g&<>Y&#Jns?WKB_QfXyrG#Z4pPb(Cz${I1HbD&{KWGV3_h)zz2%EPpnw%BHJq zyF;nUPPmknaTRN}j1?}cn8}datIV80bKUi!iEuTI?eStJ%W_Am8?^MTPK(p>o%r?J z?V^;aPN1W#z#exH(2WJ@y}t4k2i2z|N;bP&VQ`h~ll2vw3)D+q_U3&Ss&24#B*p_z z$XC3rJ9}+EITpFjX?V#?g`tpO04^KARHr^Dztj3i%33~SSPed2>0aoULHvHg`NKP; zl5t0HlFwYMQ#bWaBt}5Q7g2~-xh{MxdhavIc?oD}64My0Zg%Ufj+C8S{30c$o2Whp1%MOn0xmsxa_Qj}IyqHNC z!{>xgxxhg=3+L#ZOCwPIkhRT=3?5)i8tYD|=9G*BbYKC+s9{HEZe^H~+A!E48>&=h zEuHgQm1|ev2)!TQAU?aD1aZ1;TQ#8((xe=eWy$)6WhYI;ygrg*FY*2Ma(bBMU60eT_fJF z_X<1isnG6^Q~ewSJ1B!JHye@?{?P>Dm635*Slwm-Tx*MS0M4g)mRQC#nxTiOqIZjUe zwoy^wAx2T9P_?+UQW-3yJ>hd)$Aq*8X%{9s2fF)XyS_Y=O(G%4I`o~<>wYHOtFlIY z#RK7F^1iI;ET9#_G=^kjM`^LndEyRo0Bi^Qx_EaGjQW|!ZT4xFSVs6Cw|2fo=3Gu5rT%vIPaNv3aE#jUHI zJ8Vt_S`(X~Rp)rIs@L)0HfTK4@%zvR(GGM&kkqYuygOy&Ua_$?bltY;c(R;mrHb=~ZIJ(Y7ed@DgM2Bkl9| zXKs&b5A{LS4)Zk%`H3aYmE%6uL&((mjCHlFf}*aarI(SRaB%j8I8GU2lu6*eWJ4d` z+(RJWO@>L7WM>}X3=Jyre?<9HY-MONe%h6q?&apEa)2r97PXp(XGlJpjB>Cgmr&@KQ`LeOIjXr+x2 zfOs!V@+-qTbmh9t;X4NB zLL0MLON=kRFM9$i7}xgm8JAd_UVvngKxFh$YG;Sp_kOR*6QS zODb7kKv`o!jH(VbYABWtuC2gSdO|5>Zslp`rsLZ?1sWrH?7X#Qj=SgAiA zmkU`In_ovCWj&<3ov)2@>0*gim*W(mlw_7KhbYI3Ww?5(CSsLz)>zZg!kt9I{}Td^ z-%0T_Tun5aK4&5c9g*&YA5vqXy@hxstDu2`ejJ^o*ynl20HG>kQT;9=Z+0PJw!G^l z9Rqz#;fHDBN^9x|I5p5n5Eu^QM^o|VIeAaz`$e*U+~JbIZ@MBziFrSN0D~&tHDz4U zv!@uR#3{6xCvXZG_Y@&D-Z6z-*)pn_Cw9tEyfbTRoO6m?;ax<$Gi<6g&M9Q-InIeV zwVZp3T=^YE{GEkr-X+Cc(X*|1N92@~L4CszZ>Ic1wCG!giasFJtuu2f+MrQaPv|tQ z=TS56QHiSkEH(W!b$*Vz{WLZGJazkNiW=uMRfTU{)ea;?bwQ9dy3&j=W#I>a`RZjb zt82p8K~ML~xWNxzM}Y}K_tUT##M>bGm{$+bH#h;YRD5Qd_1noRvbqTAas5JYgAXDd zZXoq?HP}J6?zq(@f$Jx5&|CO>b0PIU)|QWs>biswd7@80^EH( z+%S995viad^hn{;uzHXx&;!yX;!Rj04xZs19+{y~l2 zez({`ukO7YG<%)jCh!{+JMJkm5A(M&k@o@kWxNy~_&mWMmm52bZXO|vAJpQnRPm6I zMv^O0thSK7FM{0TaCG36d#WBW&hQHxyhTM-ef$u1utWOGY>>x(_@Qniy=W{y>7Tuz z_S*L=3Yz632KgW2IXw!ifY%A>_CM zcM+b6%dFOWWJ{^dfykGa;0-Ny0I6Wl&ww=hkdFjavUyz+6Uz)C$beuCQSDxjw?B@+O6-OzvXb`K~aj~qu(3H3qoW^<|!BetUsJsPXaN$_6Nu=bYf3sPYIa{ zW3(bZAoK`{%@P{ny#+zv6BB5Z%=CkLK(q;C3XaO3qwrrJ@Z(swKjFuLT6s3c*i;$E zx3b$KlSy5?LQa>#dNZ6c<+T%@m~Ov^v<7!**7T7YeM?`DyFeZjo)pUs!L;;;eVqC2 zP&x8q?$6tn@1`+V*+aBLV~a^Rm6}7iCnTN(i9I$ZnuI4>T%)!{o+R*usBe>LiHmuS zuq}$*`+)SqefB_0*N!Tm+0lMO0hPu3d0%;~OVy(48P_`S>siwcW(QkG9CYbiccdp= zqfYO_s=@-{a0|{_8wN__2q3>pC%sq zTGy9%WI4NODI}K<9)9T@!g^Z#gm$Muecr%$I-@RM;(T5lc!w?B44Y-ZED=iS`@m>> zj6os}!|SGx&vnnL0o&O8KNgTV&7UtIQ0?bCIDFO8d%D(XxquUf+I-7?Y5nnl?p z$##s?P=!m)s==Z%Ew3FI&q3Y?qz;hOU{aS(<_2 zBa8ZCW7Y|Nax9#MIS;x+(4i6tx0^`CCBlb1StmZ*f)_L|G@M1NhuH*d-h-MuB;dPc zFha<8(U`|&dH|60n0isn9T@2AT}iZPQylm*gDc)1WjkgDe%qnL5H_8%uiLR4AG%`* z=S2E8{GBQ|DVQPni<(eNzz472n(_;T6AT~Co-=^HZaaM6K3@kF*L|v20c!+5iIDQ> zW;~xL=eDv7R;rqc_cf^9E3 z0p^{rhFRtVsMa#}oA`7&9x3zEAo?fV!G*xA zMp=k6&?^6o3&A=If6|i>T@lWRKhsd8{}yzkGH;`DutC}Gy;H>6>o)+d^l8NL-{^h_ zIVmK8k?aSkV5I;NHLW=15?vBd#Ij<8leR`?w5Mov`w3KSz?OH3$srI=UukT54eAc+ zd?u)n<`5@wyGKN(cZSI$4$Hg9^32+xG_O_Li-DCGLrdU}ZOKsZicCh)y!nPt2=1Y1 zPQpFKJN1CR0oL$9RR2jb*LnwUIPs+@A6#uCUePF@pFDD~*yf^8OmmmT9Tkt_=FG|u zA+%O0PIXj^PYyW@UWzpNkP!dmXkiOF!n6%gNyqjs^!35xZ2M*~w#P8FIW`>IV~Lt$ z7Q>~MCf`=;(oO&!m_=Qp9I5qw*ehU3zHdyQ!yF`d&u|&j(D?%jJ8KX1 zCajZd-osNNuizfp)?+p4-K|{Hu>V|%cz$W|YI=4Pux;7PQ;~1p%TqS5#2(oOwMu?& zo0QTmL33ogmoi_h2Nc{8<^JS9^33=6&dJvx%qx#R$9d49%sY=RC(HXfdS`s-(c!5_ znwO6*Pl(h3@y27h z0#{_b)78h{#VkBfv?T3qPNCsGN*%8tM7@z3-)cC_c+jX5vC#IfB& zD!RwZl!{vFsG`4J;6$!n*E!LwN^_s61Fq-eV@n@9F@?xP zBDUt65+YkuFU&I8P*-~$H3j>1)p*L=S%mhV_yz0ZzVsJb8`%e`Aa%Yd=)UDu+CT=2 zNHVddqvCLMnO)@4S-VsU{ueNHX{ZEGf88~7;Qs`S(7%9*Rl2cTQo!(&(_T~T=A>py zbtCGkMZxtWB{O1)vsf}25g`+MH4m>dAP2hOB5prqy#|v2!!qswpr3lnV=l{n7|+V- znfLtk$$4ty_xH^Q@Q471vC#!DR$4A((y%|Gi0ry~{!*ikS$BIUm%9@Jb1haQTrpB; zs{+|-@d?WuS7evUWB5gf_{S(X!>-YAXru=a_FNW&BRwn#n#`;K+GTNsW(i1_2>Eec zhtj0pMW=9yB@x*QwC#Sk>Z8v=XC%p?XRLuBPWATQu3HEHn)FZ{cO7$yC+?l#*E2Xw zUiU-#Q&T54nB?e>yfoJSfGjX54Kqz%%4%{3m?9^fKI-A^g~Q~+A>&NjaLGsBxHpLI zemOJrD(w!N!Vs2jfT2T=oft z+@Ig^#lmr%hZMBr;2Gsvl$&!H?}n3UoFlG%hN5SjM7JtyQ~a9M%Qa&xSDTtmQ7NX} z+vASLDf1~}{Rb?y1l|dcF%63GK95dw;?2C3J@oxbm+b!}o!0gG2e7}Mlj(nCNcdk2 znJVbYFB_ov?b+$J*8!{H`Yp^7R_IpG$lp`zbr>{>2myte9ENT6*@Z48)-wMA@DKGc z?l~PBu@yt=V0jS7oZrTZ$T;(P=AHMw#x^$FOOIg8$ z0x_ApTZQfNxifv#RX|^nG0OAo0Tb1^X~8yHVl9*gl5BVz(}C&b&!H$jh`ZEw6%NysDN}b`7X`XwJkjR4@{6OFuk^RX$`Jwl zy~6c<1mW&4FCMj<4sPnXJ?wK^fmSamX#v+>?q8jMQt=(Mgo~tuWRSv(WzgLVC?b!? z81ctZGB$GlAgPjlrBh(7VJNFvLFjfwr}2)on8q8xD856DcyvK~26my!6T)3#m-!bt zglwkqv5&(-O9-yDO8R->j28^X_nnkLXy zHMzmJl|KeO<^P8!d$RT!gugVw|3{ic{za3os-`lEI?A`*{L;cQ0bnRZ$Y?=kC@Et! zBLNYNQMO?u25iQtSy|v%A-K6$LdK{KKS4d;yNS;sq1tF+jB2EP<&^g~tY+W#?llI~ zN1pQ?=l=Vg6TScU)0I8I+yOXXq8cH{7PFYY*`yBZ=VMv(f_aD9V$QTSaHh+8=;8OE z9~KtX5YRJttcnO|oDLmo&SWPk_0@|Mav*~)q~4A6FqIL=B=pL=<5XSl-Sh@&`iAaj z8Oh?yQbn0jFOATrn9Flgjqoq6lYxKGg=?G*eevtC~*t zLB%hm1zhLN%LZv&INBr&!*{V$XJ0~f~mD^bzQFv+XraLXYys$XF z9z0?CJp>CLko^QexdYkEQ|(WRx7aKB8L4P@k_pTpI*mGkWkZ$Bz5pw3PHS7IZ_tYb z1%5CVwa1(m1|;y~3y$a~rY!{R;l#)>X3Vv~DO6NTI!sh_P!wmmanj8ZMhqa;HXNRI zg%nRRx7lFCYvfm76O!AvwSiksbw873()k`a|xI zeM)slc=TNTuNApv-w-L4|tWh`e3-1_@;tntRuz&0q_(xn> zp24m14o_shtg$7&_j*fRrD@-xxs?C3@QqpqLhYqFT~h9;I^-H@yAyn02l@}&V@TP; zo;G{XL%2{vq-r_7iz#>H=(ouNCO%V4Dayu}FSg|kCgsG%KJ9TIvMSc*k zGprLC(tW~^gN%`;kjo})sRn*#$S8hDAb7O}$y@j~lP?gfoVCpysnqSbVXxF(vnv*Kq~%PsG>AqI1$w1<~>jiwQTd)bw=pj zg=N+&e6>xvN>C*BTXsa1LO6*Xzk|St>z8pmI|{1LEo=QEHhjM~>P~OG#FZBVi9Y29 zV4RRmQL?-u!x~{+t4{TOuY1+~$HfoeKiS7b#kgGn1OT8N{6Fm4YGf)o-KeeNrrojv0xx^p@d$@xHd(0+Y09j$ zh5nlYzy(NxFCBIL{_N)66L7a;UNR?#TK2(yLhzum_ zqyn45Xv@IL0~eQ>3`$|TqCj$Q(|*zFjoImFSDdnnF0Ofnn`}<9h&iMDRjR;n(+|6v z<+OBL+Htxc+dx$$s1D1*0IAZay_jAGPWId6S=+um_e(VKmuwFg4HMiS7tY^EWOF!` znVj5YI2~X%G+7-%)lF+j0bG`aOVYjHSFHBuneCWMY;fzMY{lsDVZQ#P5WX!PfT{LV z<4Mqmvc(Rrzje-U=un6PIL`sfK7mu|EBNZ=aSOg@9r+F2=%;%Jo53EkNkDbKVJGfL z&N65$vsRMIuDS3TyW^j{F%QT@O}{OrpwS<*mRE$_h#K*k3KFhnhGThjvJ`aj&LQXs z#d!>9L$_RaUKdsvKi5(ko8ztNPIFmy?kH*`gGOUYc=>XKgNv-mVzpVI7QX*$d(N=Q zX#e!@Z1DWI8vnny=l(%N{9lOps%fhu|E7gsiR)@JuLU{MGdQn%pI4av6#T(t5Jf2Tpy2DepQbj1?rU?QCn%FzbH z3J3e9oU$K=uX4<5S}UQ|EesI-j&F?4&&&AEL(xuTHWdaN?HBm*ODiTqBjOtqEo<(R6dcvo%CFX$K&r5=QvjD*-@Z61% z+&dIvl87|-j=Nywl73y4itJMdhaU+MNbFLv>AA0~GA2~Tl*vSHj3|>md_|KhD8c*c z9u@akRSf437#G6w9+Jii2AaiA&Pe!G%lcdi1-wdJH&j zMY!A+^sNVGkG%%uysr4U&MJ#L90nyltw;a#<8p=yd zs|>?t`d?LjbDI%M&KzUCAG!#O@+<3LQ5Yr&<0mrpPHM}}^4NUw$aFA=B)XD9>gk_r z98uWA37mEzgMx?^{zfjoaIEw7k9>aA9h4lSov}_Xj8q~CVggn74 zWo6FEdUn@$PhY>g=Q^OWvVhV0_*__L_N67|n&I;Hm$b9tLaw}>D^U7|H+kA% zCD;|gWegLye=XHF=!$>MgBZR=<&7FhSA>X$gkDH}cx5)SDUj45f8m|u0PTbW2ffc0 ziOh*z5&jIYvOo;4FCP3=5sG8{4<|%%Y)(yF;M_KLFh<+YjmyVBiR;#qY(J z={K5_5>N4hWJHL&g=a8cjPg4TF>7-YW4UKDd|rw-S>l%uYg^pF&>CWeLo}?PO;etH ztK4Y^)Oelunpk>&-?6mOXS0LCeA47~WQ6}Q&YVQv0&q<9Lr(bvo^6`w$L}Fou!1vj zZb%NodyzC!>=z&9*#iITQP$;Q1i!P_hlhH@OlUcz#GGyxjdxZ=c*|9le{KB(mS2=_ z*YiLO`PZX#^RLtRa`oVR!D`65bxt7dKOd6e=8NOUPuW&jC+e#x5fIGOJNcyUA43`9 zABik(TFrnz@(qy8f%}AdL9<-P`J)ec1NI2^1_6ca9>DYrIwN}tlq^YPQt3n?F{^5% zGy|%p+5zTRrK&=yv5z(4S$ZGC_kAGp6DT5vSV69w&+vs3E<2);5riMz(O`&dAJkpI zW|bTR(S&LAamyl_1+9V>gh|G{C_X{VRfL3cD!i;q8Ww;>u2@DEXpx6$7p48Br@dJO zJE0P;?0q1RK=u$xqI&@=L~EZcXkx9D3B<5`&Y#pcLe}{EJ=_KMevoeVAD28Wft)7Z zL3xFmGJiD@u0aITwL{-XI2jwgn|V(Za9(l36h zUiV_TrcIITkHr$J<&Rb}tE{!HAVGx24J2Dat%+kZT+?M&bvN>*{8c4}1p!~0-{Pou zazK4924{KR=Q+-IOrNj&_4@#ON4SA;AQ23!u68+DcOdDl^0{>`sRB_6?-=2OYEGgU z+**752pI;FG7_x(*Gx)1-aXwRoZasSi%N;;I=6M!Ye&LgCFh^{!t@GETz}4{tWQG& z1@aQ&TZ^toPXjnDWe~}*^bRU{hh~0i`ZXvH8Y3lTo;Y3@@>vNP#({I8P&Nnc@?taO zWm6dJ2c=j@X^>#rg)!QbF=vO0etrFQq?$sQ;V}N3O}#7;On*Wx~Lyya|c& zW{!n{I%{kj4MUH|cfKtNxoP-}js)N9AUV;VcIe0FUMZI!JKMDl>77iy>Lr=To7BXe zs)~y-Ue;hAlS>t5{5DpR@%ojqx_GcG1Q%jEhc&~(QK$M%z&>EoeP0ou*$pVt9ZxyDZC`N@%#w$X(RKOqV4 z@y+H_?x$aM|BvSvdBC>E;D8erhVXt}tGz5|S~qWNQ{(isk}&wNKt=1QO5kVP=>~lb zY`FC=lV6?~5bYM6s(#9w3OT-EaLnnZ7);xZXr1RzO{DK+fY$+g!eJXVH(QT*o8?QQ zz`MT|5k=_(a|)SL+0ZB7#JDGn*(<#A?kT6D#(kx?hI;)q&hn60dZrQ5iwJzTcgvC{ z`){^Z%wS=RB*a0|E0%i_B&TJg8fLjA(Z(5uEw;zqUPVLOblzsd$$clwNQO18Y$lw`*@EDcMNr@~!sMMJ;qAHN0%H^pZyWuB zHP40-;=!@y0xbKZ8CpnfN@qSx^uFjPJ1iSkeN*sWbzB3row~#C+JTR}3g=@rB)=uN zM4HXPx5!w_^pX^idkc-j+##%}Fib;}^ig!!VyPVUep4FP z^$`VVwUj=mjHVsB8fZqqfa&t)jl+^{aXvhe?-@_w^k|2fqYsBl{5%N8GQ<5V^we*K5r= zs7>|~jw=VtJLGnq?JK`^uLr*Ht{H|e6(mT zyA5iYN;RF`1h`E6 zJqEF8iK~XHAAo^Qa9PTadQ(O6ygX%bGqbYzO2uMUBGYn!C{=&(4F)EaiAC2xMxihs zdz@woC5)aO_cNa|Ap}aPoU9eS(Hiso=FI};rcLQEpLe~vBA2K{Tcs%GKm6sL>bIqC4lFDR01IXPCsfSn*Yir zv~tsOLw`r)<+MJEm8xsq1_0TOt_nk87CJ395>{QLjv-Q6`z5_EI!)Ha5%~M!h~ZU9 zv$>fZ=J@>ObM^r57zj5;I$nf8D0ntPPsCwA_d{dJI6!8N6MO`c3NL>&)8 zoHw3g$ZwMAWy`cu9Wy+lwCp%UIAItBe@mbO7^p2Jd;tD z{*+o@HCnOQ8a{_MXx#W9{$rX$5;48oaD#~cXhlEr@dnv}2hhQfb;G0Kh#MUzzcOOg z&CKD~!E*Kgc`TAux3BAeH3R6sN%nsp3Z?(`P(&5%?Uw{_{OSgvK*@v!!ha01x0Xcq zX3;T{OBX{FW{_Z@4^<7>otmjjbRvDw`9a9&Fc?4l@U0%)Lr3~L_IZ2H_jh-{>iGfo zhRh6babv{v#e)hR@SG^q&kG?=vaRh88A-Uv(YanQS{6}hg~JW+av?%|<`bC0<5tPz zET5ej5||T2_`+G3FfBX;`Vbdq+fLoIV8o{yFT4j!HeY=C9{w~tAno1@_`PwRF;kWW z#)ZR-5_DlcG?1OO252bJcwm`^HC=qW|B|HQw6qPz$D}x9e2$+dru=iJiQzTf8Am1j zDD~EN$@o{X^^YGyG7XO?e->Zk^}+V!1s@FUzhZFXSy!2xW>dPuU8gb1d27#xcL) zKG8$&mGnVC%C;QkB?`IT57>8DsbC}1*x~-weadyZ6~CiVu&n{T;=ZWh8IF(}gNA*^~e#}qJXJ!OjpnIwT9@PC5a6o9#!|2MGs|FL??{42PnD*MjL zq8Pl{JK5PfY_n?E1&ycTwOJ(+&?#tAl|mq}Euh9N(gG!G8OD(puprIAbPGea>$4w|TqW?EU=j7wQ1ZZvp}{+6X{a!=2|b z>$zgCf3z%%mE34SK#kOI*|6EQSlgGl=D-34Dy58@1hM=wR=ETjhik?f1|7l+=k5`O zg9|4cC=qh>Imi*RYFVvraS}-`RPwfxD| zSgX8JG@2M>Ob3rxh7viV2(iT(gf5LgcF`G0Ll0m2=f<`7he$^2)v;9Fb;swWWDK{)EOQFu9=n#i4!o+(Nz5GLyv;n> znzAQlsw8HeJ%W{cC>;u>;hO#Kqj7kKi=!~>Pm$Vn(jo@Wl)c1-Jg=ibwT<%0(MX8! zy2%K6U+P3wjHi)&@unqzdtZkMc(m!f;>)ot+w8dJhGn~7YP%qam34}Z_PO-yY`R#l zNamTYQ|@azu&L)L<#MNIYu7rRI@RhGMgV$c1jK>}6di&%H z!WtY}WUL1oYms&xGWT`+Mwe-%hDtN45#sFQHr4NDO^B*hok0cd&Y(&%r%(jo=RFw> zc$Mp?Ngcu&q2-%7zYjw2kRA&|JjCd}M2OxcP%f8VRKzuU-uv{+4Et)i^`vH*fFcKz{)BSB!;0$W(x;~|GYynvt%O#+P~VImuj*C3?Y zB@*Z8E|DL&e<1L=6atCLbJU2vP(=G!g_NrHUMBm~-puvedOkim0Nz1fz(xxJ2$uI^ zxP>oL>G5;=aIZ%R4F*u_x@OVQb)OtmO4!{bJgk6Fam=_Jfr4LBNu(E*fyZuOFcwaB z3|A+LB>gqqufC=Q7llw=QOI;q8hdgG;o1I(wAl?*z+^^QJ5PGK@r!C2$?PgO9YbJ@v(3yJju@sIcTCFU|4A9{Qvt$iK_OH!1w`WQ;ne?HKcjr%rJ#A4pQvE1(D+F;yF z*-JoMJI~&pZL|IW{gd(QTDq@S{$~8YFHHZ3axV8TB7Bqd|MBj}@|#m#uh@1S{0CYo ziWY1qdKmQ#dJGm#ASXs4MjV9OT}zr;q}Q?d!qbm(^#zbH?Xpb48BZH(te zY(9<~FYl6==xMc`_7asmpZNi5o}fr5K(v}f#smcsr2sJ{I7=MTjXTGcyk>pcn9G!x z@e;B8wtMog1l@FuGpG3a(j9{$WPbv0b~v$KO?I1ok#DFv zU|fUHoWB@%5tTQ|wur24dEe@un;=2?%wy!)WGwR@GZ<=Ka`$n!=xZb+OM6cw`8I@j zI-2d6c9@5sy;9CoDd_~3s)at$PN(SW9>~3;$OSH}n(2zDX;zN1?t6wU9UBK|4Ysbp z6W+!lJIbpzx2U+OrmwIvr>Nda{N=2}PwXElD%bg={0VZQ)6uF*8-TWj$mWqNtd&~2 z;7RFLH~Jt&0ny+?{G~W!L4$H}I+3yr^ow1wuM4Br0rh+iie=zqJ>%DX*3iy>`9$p& zhG)lr0WtrNcD($*0C80ov_}#|`3^JH94G~is%;b17Twjg;>?O*6hk6{ECJ8T`ehja zYoqC&h%50S&*P*>kHbQl_1mB)^DR5(0k&JRctzH1kNwW~ZZ`YQ)c?Eh4eS7s3g%h@ z*mxrEk+QyH=Sn?}tK3c9LIHzGwtqVG*gKqQ2H^@~%0hx6aXW?ZVdMelAthkZf@KC7 zY?MLXrKGSNQCv(MNDGRw=1L-zqMR7B2sW(be%t8U!#6C*kd1yDqF1$Q9Iu(A4MQqj za6J1%nEPnOC%&uZsqTK<9LtW$ruR^o+oj)SBtU_ngB&Q#UCg;uY8nl=|24>)cO6bj zb{}6(Y;{%cJKe*Ft*O4C-|m~*a#e>`@wjf=Ekt*7;jqW^qOKQlE`;e~pvCDDvw4S2aK00d}xX9)Y>C2MjDE>f#GBf6p;h~K7 z{cXdj_;}Cp66fv<`Ei}D`w8La&Z{WFm=6jSqCtKbR{1T;$;l4n=}ApGTWbqb))*^8 z3gnIGpP*+{>$N!`&FT(;y)E5>d(6k;aRX)}d*tjy-R3#UW1M&B9Y8+Oo^A@!9vsa{ z<;dh*@k8$p{7_q};)Gi5Q+S2rr$_jTshtm?YMHBEo|Jy#wWLk(7Bh;eX^1oP73^Kv z28Lj?pNI}7eKr09USL(_XMG0Nk-Wvb!0?k8!BN6Zl0>`Zu805XIQjXX3km<`9^e0n zm%_jB`rkI>F)2Hv+)|k&r8cDLlM)siWFY}wg#eY5v}l#o{TT?gE2CQ^?iBo>GF}Bp zEeO(m*oZiw^G!ts=(O|s+)O6(^w;~FiyPvi%a~o>U1#O?eyZ-KmPDT9xn~|sV6+G3lxCJl&$BZ;b z{r?&}%b>cNC0yg~?(Xic8+RwT26u7&)YrcnQ~aVXQc?u4n^-Zn_~g>9N!cT6MoiUSX%c0U`~O zmB_ChFI|4{J)RT|2)stfK|F&n1B9SiYhnr?ls0_!NYAKWPOiF$YcM%z)4aSGXCNmh zQ@!p852FY^O}1Z*vEo>?Y%wQCOSg_5pneN?g~J2IAheg|kWO5hTpz9DChvh&Qao3M z)S}W!nxM!?H^7fCu9?(b6(*0bRjjItPyi(|Jua`Whe3xjCHP5syknoVZz9Vkp$Iuv z5tbL{f_q6;AA<$qZH1ksGAjN;l2nQrSCaCTOmggWotcp-SD~p~C%++TkwI7-KdxgL#UJN_zBgJ1ukkK38GI501CZ(_KN?N0 z$ihRz$MM07n&aGLW?5SDixxr3;T7!GI9_JzrNU@Izc!$5jxz`J%bNYt;yfWBxA&R>d}99|dzLzC@l)Kx%$F&b{HZ^;-7}*>WX!T98v9wU9Uz z97a(U)n90e+;N&vDULtN>x+E9*YM*sgi-u!^Y@_ffnO-(>u+8O{=SWZD~3(7%BvQx zb8M*=3gB(35%j6_kr%ZPYKU!_FkDt>IL>>uPQ2LU!{i)AR{4R*=7%>PQ`7a;E^Xgb zwz;KWR>wF~ZVP&?5KQs$_SopoS$Tmw1BI`mR&a$M^L$C`H?a?|^tpb6cXi?@V4OQ8 zo5Xaf|IC&+L~GB7oH*zfx@=}6i6pyIS0xWgt0i^&%+&u?i1M2C&sQ`RHXaH0WNTre z|2E%K2lgYBX>fcFqYCV z;3|PlK_s&1l#rQ9mPVG*#FU}M5vTxtXE`-Xqc8QAc&Lzskb=07h>)<9kg;w7@(h%a zubcyH)LcvTEtMHUDIhUbQJ{iSL*GKkv5=|2(TzgoFVxjFaymPPm9E186_LvSacC0Q zpK`~aqER(}Rk3J*+>S@`S7iuxyzntpIF5uET&T*f-tgjyf>?GIDhyn_cysrSQWRwE z2u}`;xYp>(jqdcS6L3E|b68n2@WuRl-_z`=rJu%^u$}ataNCw*Vezki_bdC+5Yl=% zlt{%IxBCi>1BQ@*Vej;Dq$Q5{`r)H@QOI>$T;TRO$-_lxu`ca;m|jH!c!(t4k|Ie^ z7bFor8dfWj}%kz2NT=SFI# zGQIp(Xt9ib#vXPw3{#1H)eAxdJdhyS@q=-5QTC~~WcYPEBbS#wlgUK4kZY_B6Z){m z>T84eY{suUZrbqI@SjgZ<8{k*Wphm^;}vn>%Q4llwRWMtY8{PlX>DXm9Ruiz_miOS zTcqZ>orl9PQ_YyX*Yz~28^+b)HN$wpR*)voM!)n!5bY{RV4@2VNe zf}h_;j7*Pq14deXIM0qREq8YJy+%dA!M^I^Le5%3_jiiq{G7n`_Ap)x`L+Tntul{b z33E*-5wM0MjK>jjW&;VSaS5Jp!vUFYEM6`%fNsro(4P!#J>Ao}yxblmuI1)ycvcYi zN-0aXEoN|8a+WRv##4~MdRoDd)Z>2IrVSHHio zG}+;=+j7;2_We13$4Yc}ZvYCZV@;P3j0PiZajksK=jj}x(s8dNZD*Ik@Kz!=ape77 z+MXqC7acG}w;TeT4VJoOhx%@H7$5R38v32nI%_#{ZJpo-A7o?WCgb#}UQ_Dw$sC-6 zBq`Th8sTLpX!kIm!O(!AQhVD^ZLd1@kY_suGUhH_n$$Pri={%bKTn!K?mJfWUU4N0 zE12X(92kEyu>@YuMzJ2^bEq%ZMT@JI$}HZ5KD51QoKsa^C>KYx7l#gwI9B%ft_|as z@>~jf_C#zUy>Pu51Dl3g>olqC_;2sXPa7q_{i@ zripaMV6aH^4g7`kJo5w@b`sLKCyHs*_%;cQ#-e|JJ6LMShUfYD4{>4{al*sABORP6 zP75tJM#~ZKreK}c#9nXyWxBrBkK^PhymIHEVK;n4z`aN~WalQSPo(7TK|K{1ZO96t zpU4$bdWcK8M4@;}Mw(5vBoYieTW5$Jv+Nr!g(zvrmrc27mRdy*< zXpnE5Snw&lNkB)3siX+~@O~_^vJk_|;A#kPfCh|%MU#ieuPRs_17AV91vU|;p^rNkAw!wtJb_xz)#;|+dpC{Y0U zgfYeeb;gn8nVt6sOJg!({Fs1baotJ0M5n~SaaA7fD}UiP-ok~|qD^ZEtfmO4`=Jq8 z$0uR8E?5XZ+MT1iHZ*DJSu*3CJJ#C7iK=pIEIR_(Fb3C~y(sOMNZB~-*OJNYXlks- z+g7zz<~yC+kvitqy-p(U?5`*-3?=$=I*Q0FO!4n^8?b3oibY0Ud-?lLQd#$Se{YDdY~fF~ zp)?kaVK%TUHx8mCYt`zKtnx9D@)i=UdVBm%MuA4M2Y;imjzo~Yp_o?|rDUnWr9D{q zsiy!nPBoE)jfmXbtM}vrkB2Aw{M3y{!aL&|)$Y;va>-JD#0$03ca!qzwfwFYEV<~T z!&G|8_7GWGQE=7r0AGH$VJ+NT7%Og!?6DlIir%Hu$1jfL%?Zapr5W`BxP@e0h@MHz zQ}gPc{GWRa4o>tM!ta5QR*dW!ve8bdSxM-Q+LuiQKo))NG3}|%3@Fi!gZk|Qk9-SW zshmj)e}h^vKX-j^T8<}7mKcmS(uGiM z;;>_${2Ef&T@al!82MKgmVtzyI)btalwU4+yW#rv{K++0|CKiy+D8-!Wi987kSS~? zb?1l>okECII=|GQ0-c81YTjz%s0tX)&tN023EdW-i^#l?h6NEBrMrAq_X&cpS$5%= zM8XO2mgq;!p4KadaKB zal%N;H3^#J>u@g>)y>O%6(Kr z>!7Vx^WHV{h0;gnxslW>UZ;S@Wo(k{DnMY-IB|teV{8I+=|Rgq$l15eCzzj^w!rG+ zEw#-%cJjn{`ja6jpf3}J6F`wBbPGX|#sla>mhx1?*0@z@e1!aYB4)mM^C5W zZFWITHp7roiS~&0Q|^^X5M|vjO+MbcLIeiGE#S&-Ao*d?SepbO4wswI8)g(f62spc zYtnlvA3XM5<~(+JO$1VDJ#zAiG|G_`U%sOLKHRivj2koHwG}~&xkGWPS=yGU5FBzS zh<`*Zx2O+?WARg8HB`z2yyHy$sK2P7W~t=Vi{X2v|1n#2ptQ|JTMB%HrO9tD6kZyk zMp+lSv=6?@e4`}MT`F0gPBpl(qO{oL@e@k$(y`ciKCVA2sq%76$QSTqlBr=j-Vg4p zhD;&!l?cSAeE6hJ7ypr;Qq*sjAwVli%~iz(Cl+m+KX$D9BlzSGD1R>g_%3GnaQSzD zlmb8?r5H*=mnhA!KM#5q3H7C|ht9nqNq(PM)fpbv=3!v9Vb09nm4ex-OV+2W)R;|G z_d9&3Es8wDp(M-DzMVmp%3a<~0#4jfHQ_kKiJ{sfEqne0d%K9f4E9ZbuQ*-7PtLd-o|%#;@L>wCE5*2?k>IFaQM5n-DU+FJ z-E_b0++h50p-W*gPf6&e+I^j>FzWmc&h#i!kxAe|2t7fZ*+^r=vGJqn)LWdoHoD`M z*X~vj9dLqY{P(L7OpNUgg~mb4h^nuZ+%~eKb1qBwxMOo_&Ctbsku6nW_thd7zojnn z%NkVsZ?J7oZlez-By>dQeHEz6oXf4T5b7@l-pudGW)9T2suxUcY06cqXr}nL%PumV znWxDr4%Y~!u4h8;$ocFme#KA}#G2y%y}!A4YY@%& zili>3BPOx{p6x9lk-Mm1Uk^B5kCZ;nO$z;r^qXQP%X}J~p%21Q2&Hv0UEW;EYUBFv zWvP%G>WO`#+-knZ`$GE;`nklg1*|;otbIDBO1l~qH5mdx>Xg;#cKdc>>!{7ViI5)U156u{OE?&Bq znItTwPGnHrA}y&lm|W*k;z+N2)BCm`i+`JUlNQ0hf}x@9tr*;X2yt=B$ieqB6#jml zqkDH|xz#@EK46(ni5eS-gMn8$rq_Sl}=}* zPeUkaZ3#JK8vzOz$d)Nyhgm6tkEeFa_nJ9O9ix@i`V#VWOTk2Y_^brT7!R zV0E!6=mHaZo~*1YM~qJP@kEnj_+6aPI|KabO+dvDNv@jti#mLnO0or~5-aBaM3``( zM|#|!WP<&8fAfvCKs=W4q<{1t5xZ|Q$;c4sR{IE<33M~y$jNE?@qjF1IL8QF`8xW{ z(5xy2jF`A0L8um4HnHUO^|23Dqjzhf!n=O{fqoF3^hBH{bL=Kaw)OqGZgfidF$^}L zG4sU3!nF)<&JP0hkvNWxkhu01Gc@i%Umz?DztM?+QyA`IJOg`# z-P_RdV!FgQVK+%LVBArab@4Zl}^SS)3v zI@se=L1O#|zuaQiCO9GyLa-iI7`I~G@?YF)(96u5@<#c0C_}tph)Va1^t8i;+KX#? zCygAlfrU7{cFfmBHA!a*-|scPK9pe7nS_?txj7`X=@~5mUR5{3{6N`?SsH|)$m|-_ zW~(7~PA5LZek84p9W-LAL51a%9gHWUP)CryA`5dXMI+L+JO3w~%wQXj8vf*T$~_5p z{Vm=hg48_s0-wuzjb9m_C%x{Aqziu#=`eS4Z| z@I)`{Np75%ZC0P~?x^48$jIf`0B#T>5hfiL8Ni&NO?rhZL+MN7R!JNpc>H+lSPEe0 z-u`#G;wUy?yn8BH?44@#$7V!;@d7TOK5YcJ3A{95byp2FmypS>q=PFYMDk~a!{hOF z(F5{89iS-c;4sXaIFnWN)vU8!E+WFThY}wy&i8+SyiF7&+q*v$$2e@UPaZgBkZUek z8T4U)t786s>;iMg{lOGEHO9)S#6=r9->Cm0s)dHJn!t*&yscVI`}GN_om-M# zg-X-}LIpKXyw@SCi_YkYO-nh9fCZHJ-9Jl&=Bh|OI8V>i{OR}q{Y(*_7L6sT#6fd1 zl~n(ugleo%wM9o07e_NQ0HdjK-hiN1i$>ov2RGg72N2Q$XU7kKfhV}jO)e6flYlN#thuO8%=DG&3oLmLO+5lWrY5S+6QYQ?cnrX(ESB ztWw#?df*0Zai*hUJ{41(AZ8#Y`LbXIdN-BRakJB?@XxHYYhSku#7+SSaJ!bKYiR)7 zw(>b{+w4r+>|#q^N)^6BI>f?C@fzVpWjYyI1GPGYG$)4h)|7Ik)&^^JQ1dIw z^it0^*;n3ahyx-T9D+y5U?jG$tnUU0syYQxN+N35)voTWq;=$M1`JgslqIx~Z=R;aK_tX!k3<{e?d z)A*?>idrOha8l|^TXK=2@a(t5+nXt0|LKC&lFKpW%#9@!-u+Ov7_S?(I12>xi9W)o zT6E-Toa)>*^smWIfU3cGttl6*$!DR6O##;soT8nH>u=3JsYr$%eA4>HjJ^1v(j+0| zaA#*3p<}Iy82XFIhjfg)AJ+b+i+6sO>V{voS{ z8hk07N|m>&GyE-H_%y|)^KPTU9k-&pAAAEJZhjMYGW~`Um@*%d!Up6p)^esT$iG&P zz77kTSDT@j0HFL*mWTKShV)DHP#f+E zzS?A-zdpkaSJ<-TH>G^OWOeo&@=clq>)cXvJUuk5* zW+gSHfpo%^0&CqqzAftD0LmT*6%ze|o}qF>`cxFm(Fba5_T!mpv;qG@6>ATTK1gJZ zV?cO88Kn-E7_Zi3UWG+Ebb57_Ph3lQDxY z05i&IWjv0+pu`WPHYeCAxSvGZi1mCVj7W9GXRVCZhw;~QG<6Dl>awST6~cbAI$zXM z75~zv0QBa_AaToc!JQG!wVO?sxrS!AMMI$@G+HM3NuCgSiF5@f_yVy9CwU<(w8Bp_ z)oQx0OWEj%!|B5#_TDm0I~Y;4leTn9YP1bC%ww6OX0l~;^a5&_JMis>rwSf;MVID9 z$Npxwq$dxQ<}DEC2_dX(f5$}e(AX1=U&H_2>ASRfv_ zss1tF`Hupj%AumH5BP+9WHeJSlO*$H;Vwr5GsM*I4No6mZcn z&A80aBxDVm%H~awZBl-3ZizOJ_sY1N8rmj*d{Ta5l{3saRwvB+^o+_i6g8d-w{ycKG-A-5104wl+nQ{-@|4CQ*zxB&ScQiJD^ua7d=RPCJkbQ*~D577!; zTaP1mRk-%>TX+p@^W6of8VW*3VoyDWQ6e zp>gEy>cQWIV5geynwq4()I^E~N7J#sANKIeE)IG9Zk@nqC&4311%syDFv%%L!NR>a z23nbpb9TD7o{_k}zI=~`oWs>wr!+J1joSNChgx+ib|;#5SI9m*LnJe$h*DJ;*Nxd9 z7f%~U$eR8X>X0494AIp#(~6gg>o7}j#^tc*e@!DnvtXVIPpZ?F_SPslFJfLcsxQu} z9M*#89cnuRkc|&mh!EUgjb40%{Aak5!h|qQeX?DN|I>E;(O1h*>3~eu98{GQdY;s1 zQ*|peh1>x%l|({ti#UsUk#9qy`o&Jv(f1u3Ld)O6@DS#Tew9EMx`Mn@+q55L8EJjb z`}14p!(D(sWD`KvdGpK)oWdag*VQkc3?wVH8=AH6#ay=h@>-@CDK<8)hVgmB9GJzJ zUmkxzWrU5^&$>G7=W3zT;W)$B_aQpTny*d~mA&J@3~AaH*%!W^5Bd2i!hu9@RNdjw z+u9_p;*7ge&hK!mv-C^YjZ*s{+_7fc=X`qZxm7OK3!xSb1xGzpUDM;U?)5li3>om4yt4NAq=`H#|Yl;ra%5(JHs+S7x`hI-l!KwxwlPd+2L6oTPjkhluFQo;EG4 zDk{&Wfg}RWHFpQcqs&LHFQoklK!jB5Io#2PA+!>=m8+`UM&1j{*iF@y#cGdLk0I2# z?9X=Ttjub774L~3hWDLECRfGBwaBK@#2SOHq;BxA@nWNWHK;JXh+NDn)!id0qS*?* zzmc^rN}tRp`E0WYk3pM$Y`Qc5qsuw8@G66d9?vvH)=lKsZ*;6{#_dkt#M>x)H1#`r z;wb55>R>d-i4(95w zb*rbBU)dS*5fy6@6&bvv2Hqwor_c3&Yr+0>IR&a$AYHBksA7j{iq`+p%WF!hK|kK6UapMCwk*@Z z{ysLRPeGN*CSS*9f~;x5&{PYURBndt6o8Ou)Ot=)hc4ueeMc7ng?{m#I}C>TjWa6e zSvzNkm1XMX*(E9|xIwoRbelknDS*Bh8}kdmvmUem*N!c%Z9gJvTM-GT7A7Tv-ul!u zBL;M z^MD!o)_LEEbP1sqhrV-_+0rD8yCC%F;>_S+vM2&oB(HuAe_6ooW5;Q29#-Xjef?EZRyk zMDEXd*w3rCf+xkpb%o2l{kn^4ljoeHC7zuwYr_Uen;kHn9hg|IzbbxAyv@m$08dk3 zoj@JazP`F3z1q|f+S(G|v+xFWV1-24@eVLblip3fsNvfc+}TZqa9MmJc!;zv^(MFo zc;MQxW;Z|7JYR%8I#Hu!DqDCy2W@oN7If=`*m}1GaR%vK*wN{&?yq}u^uZ60@iDQD z+sDcOJwqFfYp?6aq{&8%Rfc>%pYI_Uo%c273|x@QU~{k)pmOWGD63=DK`0!lxxqxF)` zBm@Hk_1Hk^=XH}_(rd(EV4#zKQ2Ke@lb19z85kI-R}V@*FDCMmE~5ei1Fe(-Nc&+|oJ(ta#pV4x|%p!D+`v6r+R+fxt%2Vs2saoQX!;c>{X7@oC0)V`1_qkn14=*FjlZO$ z1)sjPzuftAQSnPUQy2^kRA~-+?&q4(mvpP>liuVn=YFmud`S}mo&sEdp`YugUeZ#M zU|^uiL(nUKE?0U<$I5_#fhw**>F0`?m$aVj(~eJnx$@`H?U(e092gj=1_$)q&jYJ3 z=^||~Fwl57DE&Ny_>#8OdFttZx$@_Mtv_zwe~)(EC)@Pzpd;w%pNC0aHejj$PXm9m zt$5ueE;JLH&vH=m3r*89azZJBB=d=BnwgTJi$;$o9LjvWWPu*Vf uTIPRvP!9o=e?E-Ad#Vc1Pem8Nz{s9{emrFx-C6zl@BaWb4?HUX diff --git a/CPSTreasury/build/libs/CPFTreasury-0.9.1.jar b/CPSTreasury/build/libs/CPFTreasury-0.9.1.jar deleted file mode 100644 index c85ca66ce09656ce3cf22474a59cff7989848c0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145351 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 z 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 ak25I)EihSrkuQo?`FgGwMQ2t&3H$=hDMt|i diff --git a/CPSTreasury/build/libs/CPSTreasury-0.9.1-optimized.jar b/CPSTreasury/build/libs/CPSTreasury-0.9.1-optimized.jar deleted file mode 100644 index 6eab7e5bc2acbb450d98e40b8abd2fd72654733b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30631 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

8m;C=EZ)Nc31SR3u@8%E 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 diff --git a/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar b/CPSTreasury/build/libs/CPSTreasury-0.9.1.jar deleted file mode 100644 index 4463b7c11dd787518050bff3762f787807d8f9be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164910 zcmb5V1CS_7wl3V>jor3w+qP}nwr$(CZCkr-+qS#knSbWRyL0Xz^WLq9%!;V^7OGZe zu2m81lamAnfdl{m2M1Wu3sVC4>jL`6^w$OP*N_%g;-?mu5upVJkoz}aY^-&(>|X%Y zzXsBO1xoYFh>Hj-D$z)bJV^hUl#-;TnS++3rkMUS)2KkV$hdoSFa77wg7dUE6-|qR z*!0X4_0%L)`QoJ1^vr@J4cRiK%rvdUk|PW_47r3f6%BQTkjaC?ode*1aiClK-#rES z%K<}M>wk0d?-=NRVayF}ZLDlesPd8esMvMA|Axu ziQAsUZ@txo*>63kA4FTW+g<7IirW^>E8VV}<7k};x^pvNYpR{))Km8ssHsotTD-(JL}mBm>VN$i}|u8UeMrI;nXY}|&lWihtYYExTT z(MLyvBIR0Kc}7l!MM+BrDU3A^EJ^m+DYhKnRqD2ymV4!)jO4VqWGTwtFdS<+me+SR zot-}wmh2ak6OJM!YUHN^_SmL`jO_-;c_vkHvVGZF0z&BOs*%A%TWV-pTTUn?%)REE zP@Tlj+Cg-hi%SDNVzLH12Ube7lc3VX8^q7vW+q4b+YQ4RIjhhk#3Fnk7TND9 zoaM4>=1L5bO-PihE!V%I!u#qpg%5pCsMlsqL4t;VK~tk*#;@+^w>v)Y#w7nW>?Q7$MyN>C0&s+wp@T#u$Vz}B8hMVIfJ=466QG28ISi>SFgMLEQ!UqR+{o` z0sm}pStyt{gdoZU3?B;Voj;D3U{#FuCx7Te82=#dVCdd|)kTIHE9o`Q%%wPse{$jj zNy@n=Nzu+G9CpuVj)Ku$`GyP#S7ZbKQO{sud9RINB%BS}806g^*aTLIi5u1z0r$wN zLeL6N)&n#?ruurF>EYmP{#-!X=~4ocKD@DJHMuG)B<2rAaJwGK>-%m>AH*X&p@kk# zut^N?MxQ$Bv2x1mS(dY@Krka7(lJpF{1JTauF&$(*$mPY?g+u1G#!#h>Z`heKA4HJ znKjBm!Z;Z*mDQdVBAD)!>b;2D0lGPPKs$elDmi#+R<$x?8;6aM)`N`jAh!o%2OlLe zltw+(xvLnBseMp&n*^cxdZ6i`S&7>0v33OboeXN)zv8tMvdv{nTEwR<@1!%8qFB&T|gum8TL-CnLVaTVM0S6`9!a}OnyosoQtAb;D4V$!_#rP$CS$2#lsBeIj)*pI)J74} zY&4(|@!6n4Y@q}XtZPl)RjjsLESBw?0@W>7VFJ)4W$TTy>CRoC!ZCyG^39ves%Vv( zGFF+`cWS8Bdh|WuXd=7wr}J*!_YeCi8cbBYJ=Y` zW~|z*e?5ClX-J#pb?$$S-Bft9)f-}KT0__K6RZ#1%DNRuL9F+jPL3;M8ocqL0U0!D zj01v(bK$KGgeXU@gbqd(1?0;SZo!ii1@Oode|~M;#$~Y$i#W{c{Iu1ZwV>pid5UVx zoqUstDE)#Lfuo5YI;m*R2pJ#nw{ve^e}LY& zkvb#`fEqCtE>=_@boK&az<3e6GV45IrIPO}he`J@{J4rqkw8S7R5kTT_DPrtM}7}i zt5BZ~uM-dDhSGm0O=vj}H#{B4OKa<|% zRGvii(ZH!8X@#gZG(kkyMukc^k2$y>@Er5nD4lm6weqcBW{M?-uZeYasfsE(z={%^}rtK zfu?3&&39jkHgW8(!A+S8XU}Tz8JP3>B3jX+>7wUqiJqXdC0FB&=edE}trvSJ@^Ek! z>`rN*6xs?KvtM_!@U<%>+JAISXdrR-$;cbB%m4N)k8yP*Xa>ZVzzfBVagTbpI%ozg zSMXKq);*}zzZG#Ca9jM<>lQSK7UYJ23%V!lc6e73Toh@@t5?mLe2Y2ry5SP!5 z)eUy9vQHJU2ket?fWa-q4lIkf%I^hX``5Ot8YnKF7hD!$)-P0W)PCXtSfEr0OTBD6 zP%g<=xL3M8_S--RUXV|@fr45bnNNnOF2(Qv@HB*R`NrU>};j6aQSb(_zUD;RYT~>r1m`{=cTQFVRElF0PUR$CITfiNm*XrF?cpuJJ?4TV8AJo0f z{#H012p`tH7e8BKFU(h$fg8{r{#Wna7sPLXSD67^5Z|!d(0*L}Px;$Xa9^xXh=E)X z--z4NyQ$$xP#+(Z1ap#a%>lKS=?%1AcDc8#S5ZT}Oa0u@nSMEcZ+~z2UgGCsqle#3 z!z;@WEypg)&I!)4bvRya!OlAqMTu3kDKAiyTybBk3ivIN1RcVHD6Uxa(7D;rHd*L+my7J9{>bkf*&vuOdPNm_}Zo@c>7J_ zCIlP;f&h)%9_Y3%cVlB?WwJFw&yDwu_ip<2`E|wlb#Fzbhl;Md=g)zVQ^9jp?(r=( z=;0ph%Gu81n-{LHq?@#U0$4T{sXP^ck*oR^4ki>kI4I%$_c7)cPiwY z@ppEt?%dmpz)#?G?Zihc$B+1S?YPjl)&3nS`IquZ@A$_J2dUF{=(O$WrwJg*r!LQT zY1dA|sPE)~?!B8P&dqLqy!cy2NWDf*jeDKHMo(P#{q4A5XoH4-)$WS)y+!c+Qd|gu zHs!N9G09sKLwV+Xnn6Mh^0`KPjr2nE*{YOvh&brFly+utxn=0t`X0$PWAGGw2MW@) zs6;C}39^M_@F$OUrfEXHa+=Z*>|~iluS&7D8K^mOXmn?tqAN=*EFeTNHHi!i6o zE7hX=Vrlm7FA~2+>~#Y7EV9_)dp2<#=XXym6S8B3dhoE)6-4jrXvz$ zLDTnYv*kR?=zE*_X5@RDH!Ou9*mkE9J8|*Hnx{)OWTE(*;1kE(cIM5lpTy6PRp%&)YEn$n%o^K zRW&yj4Vay2CDMo1&HPUcmDGk}u*WyoT00~ebkb+nmu5HDr{~tEe#hh%{D!8kwyY-g zK!X^ZnVy~tDZPtwxblpXmaNh2}OIW;LE z%G@>;s2q<~0{MBxjqRPT#@;UyRX!GV#f*vi()s$z3+0q~v8_GzrAJa@%o!RTGiu5^ z>+_op1>%pFW*1i4bA-m!41U(O(vPG2d+UsXcO_tX1$mqeJQxx&BY>HNTh@}K2B%1m zv>4%|A_n2Ja{G_BEg&YwvE{L&f*VMqg$(40x8$x5=Fvn6)N}r~DpHF$TS#ZJ6fUGj za1M5k@)`x>x9@gZ5Vx=~BELEY&?41od6-BB^AAJTL&iKZzL5 zS%w7XzM&+|#Fu+r2q!bK8F>9Do!`;?o>A7+Al&7+`$j28&!>^@HIblJ8M&oLEn zNSARj0x;mqH-uyz1VP}+&8}jhS47?o=knF8ik1}^x|o@`7?5g$v5Sw16s@30S%<(l z1npnzjo4!56e*8S?oApyL<+~p?AnMs*b~C|w7i)xBtsJ5-I$x!CE*>ynkicXbeWil zB7yvYXH7J544_23;XXD{&v!s})bJOw*zMg+%`&AV-sbEYRHe$fMjOh7&$qAwGM{Q% zKaz{`wmA`CVMPG$-P=WuGmPbH8C?|JFqcWSVQquwh#YKlGF1hsSdd_ZhZj8w2?HS_ z<>g%w9;~6FS2dL>I7Gn&#_ep)^wlNvxHMGNAHT`D`~^cp4XULf?r>Hd!-%3mO&@Lsnyi3WNtKVZwlS z`S+|N#g@o1Fu4*4GDicM4yUJlg?{Gkg;hc+K6UDmVU|7H3X;|H$Kl@sbw=;``1i{v z4(c(XqgM>81P<;8zD(>TQ6wLru6DLmnt7Xa|8~jfo?ED*M`U$ee;3D)FcQ*rQg%%g zRL_-8uLc_}Sne3vFINVKeTTORU`Zzdxm zvz(z27Z;X*5u$c3!?O8wSXGEZDp(7B2KuJ;K762Mn^)lCl;(n_b^!20~I)q3wiHJE~q=?^~ zWOVgZ@%Z*kD!+{R6dS`@zVu>QgA1o*(p1u|&)VhNYxwol&tENm5r!zt09x3y2s|Wn zSyg_d*?-!JS9A)}i#h}mdT?wqFhCnx*mS1xl&c@Uz>F9UitQ~k>(Pr85~_hdHa!pa z(!)o(JgR3pCEb(medmvX2js1qb@6IZUNx7pXA^~B$Afe3EvN{xQdY)iLkfnsx2Ljj zj!|D_*MZ}JOzv&gznJ_fW+s8JrX_IC0nf;}HzDZ#MXqQ-hZQS1sWf_4EQbc)P;KVR z)}UT-bbTjHP6|D>`Do*OnIgVPHmJ33@>>=iq(w_NqPg*&z_(SS_c$yfPCH#9nkt;% z)~<(Nb~X`=TUeH$g13q3mwcKQPEmz3KLGD4ZUh)HA;fcVputjqk9GgZ^s!!rsvNOB z&lQ!R=3obZZ!s#gb#=@1?DX=qzr&g*2m;WL5dk`Ev>Ll|!BAy(rDb=BOAgr94__^Y zM((n$8L-A`UhhKWzWNp>Er5*L8ea$ilu!uE7;;F9jv$o=3;qUOQ&>xUIf-KdHUmFp zw;ZC#EIm>Z7Cl>)5>u1(dR#s<)Ik}Fp+=lx*94aX>A7Zfv2IO+wgx?ODc7kS(tMh#>^k82xI(O!o(AJTcQ!3V( z`PzBfWRYI+mn*{|E)X-!ZWO7QkFaZll5c8vlLccclydSfBnU9$+cu$>z-3gx2+dy( ziKL-ipCS%S_y;tB?Z4ZqMrUbCT^U>^p5sGYf?f2F&66BB6dm7`+!0{5ve?1>q8D%Iy-g<|GPGL6O){8iD{m)4m>T&kaa)J^(`U{Q#MEq4Q{ zQq__i-kz1Ld~+4pbg?N1_Bmc(tKJ?(-diyqO+B_sz58Z)%2MXNEd#G6aQ5mtaV`~n z>S6bC3!j_Uq0{1ugF6G8HqCCOc(hh{h}62rcVXu<$MhS#gp`O!`P&hGOMs~v+Tml; zNu8WJo3Ijk*BG%%PjNY1ZtWVLIv)zuR1yWM&RvAKFyeG+;FyjZMsqFCUv#)cmc8o- zn%aH)D{Gf41sAse*^T>slPIc?<}1`GvSNcQg3J8s(KEkW8;$|$$C+2H^_GN{pIEa+ zVraw4MpXqSoXwe*VoEWGBV!Xj%o?sukb+hNv5$w=CsFj9nM~i7AT0{?3b|aLgC|kA zbPKUm%?|E@NiNY4wQfBZxK`-811IeI?v8Q#<^clO#SBe9sSh)6_K#K8U! zSJ^-;hIZ%V?ga?6Den7a642S%I6eY~)PQk`NsbHD*SXWk^W`j$xmjaVr}Gt#`i3WT zPrQCE6f7BYn=vrVNFL<5PzxwI*%$fVow@c#IHJNwlx*kB?DY!Ht$8kU(~Nm8>dhm7 zm-57sFaM{4`}E`3EY2cMf}x5j#~ZIi;%}Z@RCKHpLui>XLh>4KC7jHo)8~-)L~vM; z0KDvx(m_Ivehiqt=)&-#SG>TDcEJ@F^mQBS*uxVUA7Xx-&1)U&-)>`h&oKS*FBNH{ zvpCBm`X&sFA2^eFymOUyi8i7qHp|cEA4eTjE7IXR-fs#C9UE8Jb+oR~FWZ3LXPQ;$ z-HC3-C4-)@m+_`XO&dHzE>G-j>o%J<2HIErbg#dqBu-Z&ilzCL#KPy2|UAt z;CFIkl4Xwz*$eCWwLvxRD!+5=Ypqy6nnjyLwO5=_?}Ve;p+i}M@j;&n{0+_r)d^m_ z*YS0(FlGw~w~=suN5c>|vaPKj%J~vN;5SQLae~>ysa9nlo}&(69I-%*-HL4vHQn#p ze|HEf^_@0?WSeW#A1eRRg{t1)dk`f&Z>Tk}zQz(rC9bPU>DIp!4;N>FzWj_2x^(0s z!sK0nzRr=u@(REbLL=$nKvH_BkasO$zX@buHBgViLnMlXT9qg(7jUTmvuh^cl}&kG zHQq5jQ!f`&mdq~PUhpZHnjW!K9c!iLM8sl;>=pra8O{y^Z_Rx(MZ6GngB3moy6nqf@wsaYd-U5%W1J#MjEdE#Or0Cs2BGTNn^{$ z&wbs!#xmkWhGqDLf`;pCfL*1Fq10x22o}<@;zX@=*72MsE3tz@R5r))Zdk=?wN84g z(39eLviaqA4NS>Ez%Jj&R9y!n`0yY%J$oxDKW#u#gy4r2UjLYq%1c9eW=YKtNBi z7Ox^re&j5Tm17{KBRV{i-huZrh6{itbODXf+LcL4l+Aqsde z-C@A=62d;YfpCE25bC*0F8X34$z_MSj(iBvYA8I?-z$3>i_z$x+y0LHPmM{$4~;%P zC!=npA-b6yssK3UmE#9H&`>9=F2TETF>x|(tXx^Sy>CsUhubIOMy6*y@u$bD zC3RCn6M30?35IvpJXhvJbJg{$CGtiet?k0=fmJgolz^Z4b_O*|jG>GfR(YRMds`ng znZbt>Tk%F{jUHgP97J1bCb(_5*y1=DfGwzAH|dW|+fp-mRdbDHzH`dH zFi*7Y=bduC+sZqE@2T2P^ozaw6|sfi%BtSH=emwdy)o~sT2HnG-_)vK8)d$u%0D#c zJAXZneTUV0N-q1ERp!Nf!fii~&Hpx3{gPkw-LK${d55ZbH(2yNuhF8kS3 zw&nXmt?@v6((O2(l>14p{6=5&y{e!U_+qVjA1?bz(GmJ0R`x}I+L@!2`Fbh)@z-%a z_Z9k*t$DXB`$^YvJ@@7Rs-^Mq75utUfATe2JjwqA>khy7^=|;PeLFJ{KN=iLR`wLH ztlE}zhb^D}QL4M&T?;=!SK`xFlG=JiA>+41`(piy6id#LTS!U(kS}bNrd{mybdEd~U?Jc&sI{3!Y z8qC64o6ak<{V4EyM*`_Do*P-bGK>JUM)|ci+A&oPXp4TbBivKrU1XUwMIU91t%Oyo z&YeyC>^=x)y<<*BuLq=KZzS7~7`AY&DYMbydG)*|Nl_%~kPi zXit{8P$wz8AU}6V&>A5e;Z2{qdZ`LX#GtoM!%*Rdi+t1%_{POKp2#XQOh7P0yziA7 zW*!q}u0=u6CS{$c(y|$^Qc;w?%5KT;Va4;{A|KA3uF&}B0WIAU&qm^fP1-wQV$>{y z-8;*~=w^_tJGP}G#WJT+OA!l#w6HXQZ8cgEV0tbqIdCbsE+JC8N&-tov3*k~<9TsH zHD*p<+0cnC#hXPQtkuBSa6{iSRUTcNXBkb++BYbfyw>evjKMi zJcG#*A(JUIma^s&4o5||LqFQou*Xx?<^-d!(Xc1sG(-f{7{r8H-r^ z){$K#Hg$yc!os+vZX>B z56~vo3MuGuVf(-~Q>w4SANq~TP0l&qqxweevz=)%5Z>KC0QmO1(j$Po@i$^~jnoUtsGb0*|LPXnA zR6eyTaJBSAq%-%pbEGqI4F(ZORAfK9hRj{smsHeEX;*)r2qZKF7vO|{bIl61u;&92f zMXNEYM|NB2Eqb#{sK-uM=6Vt*fODiYvQH#vZ@fNcOib~1xCrBVV>{4z>gO+6Hc-;I z0cY5%8D=(xD~*>wPO0P_qsb>LrllOMT@+<2%(IrqWjq#Tbf{}k^iyJZ?gbkdihvm5 z-Bbvm*&xjMxMg-|f`0UaJ~QEubpvO=!Ga!eMZtY}1zzlfE@lY0ekca+Z}6yo=m+k0 z@UVQ5A6MXAdWCsIR(>F6@^bBoxd%sQZQba*$EY6>T<0daqG!FR+9dj3z-oeN zf_HneWA_a6m)M5i*pedp?udADP=R(c&0%xpBF3xvf_%Br5=-6QQte|?xr@i3uzBOM)_ZIWk(_C>K;-%k zOju*qIC8y2Xu%Y%(f8#J036XK=4R{p-H)Y)vKmM9bP0R3=dcVL4k0;@B0*IEgBnD9 z`|%DUsRQFrBIyE?49+xF-6PZNGc~|T>7~E_ z@xo1fau*C&&oIX~CEsi8D*8;i)vXrIesI`osw289eu|E$?*ZKYD7XgguDTZ}?uhIC z-Y1$t4ypdD!Mb7JcBy$S!xe$pX1P=+nuD!siFQEL53m=7L^0joLUMd6{{m`KJgUG> zEg2ze8GORf7}RW~5_)@XObB~q{6&E6=vc0E)TjLD*eEvPjy2{R(>GVG5P7c2o%d!y zLhA87jPYwv(%uFKb*N0rqK8OMk}{Zlu1+E5w@bjGyjS0=&z;6iB>B^*4wQuDc(Uyp*^T`OxS2DX?$p!Zu%9^abA!NojW#Lu@ zi$TZ|1b3U^Sr%l7CdW|ZakGv3KC!`9tqu64qevKpq|C2_6aipo9knb~uPE4-Bo-I! z<~l`6KI*~NSAI073@CZc8;)u3be~f2AZQzbdaT=+UleP?@qQ~U!_k1<7$`LYHQG(% z!nA5}C9uV3;Iv#P<%|5yzdJ>cI@pA@od$==kN1_5`pt)y6fP~wt12pBl9D{135jK_ z^O9?_#E;ajEQai$0G=_j!kU?2Pi_UQlz?$Xx4gK5^+f1-07Kd(I$w!A(9GUR zX#3e)k?=Us*EY!M{Eb(4J$OPfk>RdeT;}Q99jk{llR1##ikw0i*vXy!dw*qADS)NJ zYM-}b5_Zj+(ZBFP;XYO>X=H2()e-S-TeN%Xb@C2l0)dI;6y)muG+}+ z2Dd;BV2W7eyxwKbPZ(Wi!5qIrap7+8%~_;5D#w=KAR83t%&<|$;W5Wwq+}ak+usn* zT%azu>w+PDOo1@MnmKyQ!3H@n+Yl!P)OGLiR%!OgT>pjSkOKP z>!P`>fjO;Nppc`BZ-{LvhfoWQ6H*DeB7 zeWLt`S6d?L4$VDf37=Rqc;~_b)8gniZ6?sh^w!<%iEr=#S?3|&6ae99 zY%OYm-|njL0v`TlZ+AZa%tuqdjSriSIq3(6n=CYt)LCfE8n9Fb7z;+O8zqY7HPtw?z*q&i{sbP02S~ z=USfanF7mmk{c$5yU*TVlU{s4flkH}Y0R~A9TXjJ``mB!B&3QbJ^^@WO!(=`sU7G} zrk?Eq60@Y0poeYP|4btR$rGF|8mNT6&j3VTBn!ncV0xFx8pNsP!6a&31os3A&Rkb0 z_e3&oT`R)Pl=CZswvhGBp=eIk@21)BbSbQ(rho6-2Xq|%wTRmZ8di)T=#)s8zk$zX z(ch>Mc-+uhYH=uPRCG z#DEBf z?NFK>({JJG9~1QwBHWoK+${hHxS*0#12TLVO}U(Cwh)fWwVhGlO~(s;ZNqg!Wyk2* z`4Z zDPRwFUnejY55Mj{XMEvJAH;{aN8pXfm@h2uRPMgTHpDk9UR@8YeE%0)H*ck%8}alu zs~I2{F@vj)1+YBKAFy9x&@6DJ8@CI2pyi1?vCDIl6R;j+;yZGtK0KehI-ugTTY+vx zDo0PSv!d}PVpesbHh!)ttGo0a5v=)#s=Hh|U5AlMX+WjCggP$D5D_b$>o8IC`HQ4D zJ+Mmc^WK0k23aLWMt0<|a~$>6q)W>xpl;D~(5?#JFffoF$_~to#THpMRZZK9&kLbO zk+$pNfmg>JAri?`wQ^Y?=qZK+_QM<#e9QOY5~pDg+0=) zt0?Ql_n5|G&&gQ=1(I$WCc!2muN>wGn}FeuNiQOR#}uCD<^A^^ylJOA1@UHK2G;DIDSnci z+JC4~&wCGkXk&jdpQ;P=JAg5<>Pz{ZOZfw8oL^O{QUzmx(^i=;UmGjpF2nUdh&?y z6YxFOThx13drJMy+&$IHAMmYd1VigU-3wCtz_4GV3Q)5{NaC4%@R<>?lj!%T@m}-} za!?4qMde!n-0J|ZP2pSm*PRf09QR_E?E@{F)VChkw=c*+6zLoRVGj^U~ zJK(W34Ytr@o8oh~+QKdKmHf3=-OK-0kjUaTm?9Jq1iLnEH*%3UIBESdirjzo!Juk| zOO8e!{(xTWkye;5F1DE?o>p+YQmVhGtM$y<+0l;u+c#3ccp@G72tPrtoK?%AMX@uW zwuzU5N^t{7gJVmT_2Uy&HDg95W5z4Fm{LMj@!gYKx0ptCL6@$kzt>W85%lomY$_1q z%HHA6h`&9*d;V{Fp%b&30NTDwse&bD+2yA6$MvG=hL zId?;*N@i?Ev4zmA*B_eXwAhW}jL@Wnf={gW*di0O&vK?@mHkbNd`OPym_ii|32QU+ zQm!6xl1bJ<_b_(LroiJ{DyakeEAlG{NIbYi+@hpg?X+Q-r_I6~!}E4oZr#+Z!9Bl1u9rdk*^quto+0#<2YVL`-gzQt>^+zmc^*%b4CzDkTMFUE$fg6m-3**ojcTk^J#2)aP`NcNh23@`o=shY@3( zP`v>3@}%8y+Vh(GWxKJ9@%^4R_Y1l&`jsF=P%UhqgsP=)$Q|@Wgg(p)3M1Zd)nLhl zd}iL8ik+&R{&B#tx$is}4XkeHoT2ii@sSUS^A1lE_U;xK$7gJCkn1xn6!+m!RLvu) zIG5}-Js`KzO=}p@D})r8YbhXi-yC^{%uQw3ks?R+HXs6Z?K2@D)%`$KsjFh28M(I7 zO>j7qVq4)33K_BMIhDRE+Epn_?zSdCm;ANakL!BXePgL{Fy|!A5p>25w8?&wAuGP> zx}&PX#Amx(+7%UaKhb90CCX@GuKID`%t8*2!;nU;L)GrLe?7&+?4kQtK+d1@WdVnf zPfe)6{-}ix#RadlZ%_@cjfKW?0h9h)kdfZxm8@%O62;?zwj*??5Jb1_-DB&?=Iq3g zgli*^_4^p_Z86V6P|+8u4FtCLs~fp?Wy`uHJCXx5nqm4UX>QbHJ?~xR66?ye^0*U{ znVyxr##Wm2ZG(}y)DTCP{(@O&FjF?g;8u1K8CL4`h9IY8U`6Aw%oNG-vE$#9nB)Qt z1Yv-yQjJ|e*d^{^%bua27zo{^pctZ;zmr8aiptEVG-l?NrI&&0 z<}{hcNBfM{r-`LIESFmz#trbIjJZ>1FvkCAH7GR~c9bg0v7D#>jx4=wz$dn&xP$Jx zRNDa$ym%NyjhH$PEO(kE+_8s(RNbaOo-&RZ?YJU)R}5)2GmW{3$zkLg%%|ooCtux? zADs@a^|US+agUViXKWlN=az+m{k~CWK5vMXl*N`X4O|>CxeQ2TiOI-ne7+@iz0)|~ zH4M3sM$fWQ9Tfj##uh~gNn`N}?IZatmv8BYb;9%sb7L;H7ZzfA>j_;*#XUNYCOLE9 z4ei^9%e*;p9@(`o``Q>{ucB-G4~yTFBYqF=x^dx%Jt-Nz1!EBB?e z={t(%y!y4M+~0U&sqn{glW0vVRsqqtBuo3T907yoPWoV}f6)#d7h(JziMavPBu4kkhF{4yUCwsmfW!*D?a!0nh{}w%1=|GW3mWxQVdv{zhFe~~n4O*4`Z3k*PO z{TL!MVWEf1*x-PGLQVx&ohN@ zqVl^^vQL#nZq53STe44qL9a+cc)K~5uvkLQkcHX#2hx55?~x}H%ZDCPX@As-Y#;h2 zzpQ^_TcXLF!5t4b=4ty60|9WQS=jE4+2s$obfsAg94>{v9CV)sY6Y+>{W zjuU}D&-;>n&CSCyxzk65oD zD<3Ax*9Ds^%%hpc2^M+R*Y?8KB~i;eJT(*CN$a)gaLJzK1?M+#i63Ph=Nph&9r{u=j%xTUQhxB+;x5pE^~r1D~qi*lAoAoqYgoOR?Zji z1^d`UmK#!#iM^Rrbw%?00rqCXS3Pa?l_hA%bSLGW&p4Vpbk9RWZkayqWx$MwUWtAf z{&H2N{^Xxo!T5Qd6 z^EuwTV8yx7HI%Hint_%1Zzf(Y$OPvjj z8iwA&esiz=n)~e5D>M_k!i1on6XA>n?ERN+9#3RrNcd_r3;RgTs*!LXs20NIp2K8E zKqa-#pw6UHwJ&^O?!O1$G^ic&;;-Oi00RIJ|L5TU68zdKcMlt`05kPheIr{G*X(Vv$rvhg&bI)t)>Uh6Lvrr;h~>HrN!{D{flm_I z;32_$B>PunIANE5uml1c{*dlYV~pneJ9)*j#?!OV0>~c>O5#OI=O_6SL9`=WGK71U z@fSSuhBSyF#5ZJY2f1yycSff-7g8jHKJ;m(f)-0XB+>*6QeJU}h5H#+-Wl9DQcUI) z*jIFHwWIlB%}U}n2lRrDs;7$14Wo=WP}B?=hnJP|C=smlR0@m~tx~qA%8O_z3sS`t zCv$I&R}Yg9ccS$5cSFIUInmCjn5#{9i^C{hA;~{lK;>!SzN~DB`21JskD~X;`%aP} z=W?gm8gWUQIy0BAtmX-p@C%p~@K2XgwBi)Lu@=nEa9r2A(;bkEtL5PY8S8fezM%69 zd6AG`0>_m8=^OYLa)*hghbPOu0p2w8&JD>xRRhEqG7x5ZIbP6EW(8VEy`(PbUX99- zEHrZ4UqF@*K#q+()M`c-LkzO>dFyWlC+AHtkwXC4m}Une_*D@wDP`{@dnovmZN?>x z1pxya!WW#q|D|{Q??l1Bc$)vxJLs3GP#Fxj;Gw!_g-8ckcJYoNFKiT70w zFKFXV(%mFf=bB_$%ivyiGC^)(r;7;qGI4s_QFL;mwTXw23ZJ8THDA$o0B)U2D_M%+M}<=!q<{!<~EZ5Vy$> z?Hq#o^8n8j)$5Tc;;GX>r|E}UN7$lT_t~+1feDx z`Rv>TQI0Z98|kG*qeThnIw88r*D6;+J4`aHlUEM+8_17Z!#corzQZ}pI$^b4qrh7_ ze5;bUV4n)412+Z_7Fq5Y=hg=+0 zK!0$c;Wl0;99iU|hNh>~{}YSuBEfSKoxzwn0htv+T;;?u$|bp{G%yi_2(@O%qQ7Rs z#({-fFHM-)m^#2t%A5=Rve8oSbbVRobqc>~kZEo?hn2>{GBti73Ngpp#PQ+Jf|iu2c|PBmE`#UI7@usAIu{oCT?t0Z5H_K`>zJAxKSzKP zw-HC9io(EmR3;aDiehRT??j19qY3(jL=lGZ=e+@!lx3Ct zgEgxq8!Lwh?-R7=sPTX%tMmNL&_tDK^>LQIC}fo}TOC{mxN;LXEjHeP5Az;h@o)@A?OTSmn)GaIgEH z_2G)PUv1)*McU^%#Old;`8m^DG#9QaW}FYb)P}rqarDZ`8Y{O#L&ZLB(~<7savPr_ z$lh;3dmi^Fy{PT>xnU*!JNA2wZa7tXJyqU-wUK2jrH{L_@D0EGC#+Uf8^Y>H@@>-IJNA>saOZ#eyFKcQX53(;z+Bez2MuV&3}XNiPe`If>sNz6eep z%e;4Ckz`W#@3}XPE^%9x4Mkd*VbPtrAWQi-D6O^4eQ#vup$rAczlugHenT^O>joPDlMlADG zL@^lnO&BV1N5E|M>nJY?i`0}Uh!dIE63@>DvG)^* zQ4qkzmrxSb2DDTIGrN%+7QR<=VGs#;oOR_+G3jw6Bt}{31t`QYK#mTo&lxCZhAbto z`_=s>b8$?za{N70)^mrz3@J$6OEHcsw^jFs>}45p14k4qw!s;iov*jS(4w@bx=3Bv z1G$3hzUtyTZ%FwfT|`|JC$W;E7gn=zUjwZyms6`-WzYFX1#nuKTKkZi>dh|A2s|n*Nd?pD|({+}yc>Gi6B1JL2MtYsJC`gNNjz!ufZxYHtC_ zPWBX|RfsDxHAg{Z8LDlaX|i*de&I>DNJLl;;T&LuQ@97)gmJbVdp5-Ne1f}JbZTe2 zV0v#X4hi?b#j37JskGtz-9RlM`*>S|GD)bM?1r(=Mawi+VH<@J=j4;81HE+Tbm+HhfAduhsJ zZ24RN$l~{aPJW?%GUpiptDgS?s51@{8+81_QM6r!Vphu!X(`8w5qtU}(-frXn0ZQ8LXp!8H@i0Z!J_U&`SlJvG~<0mN9Xh3GFN_1AkNWW8B6@H zx`*|DmbnDYj14XSm9vs%`y~eXkg`^a!b|2*e)=*!?BM?wZ+9IWN0K!NToyAkvn*yN zTVOFWTg=RCF*7qWqs7e3%*@P^rITi6cW3r?@0*LbxQLGKzp^^2@ z)>_NO5C?T|LGP6Dq0e&gMAA}-PT6cpJBc0?R_fG!zGd>s?r@k}0=rHqgwh)g$;eYn zq5d-=Zb_ITjwJn-<1>LKje&S#kQdN)2+n~|1cGdz9y}2?-JUBDY!uAp;Kq>Wr@xN* zB>;#(X7AL7&pWm8e|hEpjBdmwI=U_Qq4b}d!5FDB#v}DtrENy_gl>n{J4Evln|1F| zd>T?jgN&*K4gto1k1acUH#aEFqw^W9Q*w<{&f?CJ&eG0W4VTund4k69ZufPA*4JBI z@6TEt!T20kUHj8Qt0*5)ewjtO*QJ2G~ywn~#@-8;+`-X^!>TT*>4pQ(((ZHOa_}nheP*Urx@c?8Nz>uKv> zEYys?P8Q7()0h&YQP-y%eTf$dU%+9q`CjTaHP<$+MpEu(O9P#Ww+&n-O$&U zfLr}wH|!eaWv`;HpwM^Xau8k-j}u~3e`hx&KiG}N#3*|bRq;{7*c`-XW}n+p2(;uP1 zJMJuu5g$0J{Ow5r@ikW5$Sb`SH= z&txrF5K|GDVEU(-J=UbpGg}_iJ(}3hR!E<#dJsmx40wIj+L($UmZN#xm)`o79Vs&) z^X?1maF*=BiMdHLHOq?T=Hvv;TwLuzTwvE$g-x3`Jsx&bGM3jhBukex2k1B8C7q_p} zUN{Fe-xfODAV;x5>b+`cQk7J;3~lDpV4=snKd*?m5e*UXXd|c~HS?-5dBTVEuy)E+ zHua1n08Lw!beYt!(Hz#w_H>|*v21RXG}?@TTW}GP`*~VK9x8z9h>Xn@8>{265|*ZfiaRi3a3V0 zTi+3(;rO6^pWVq0nK3VPWXiL(<4gulz>(CMJNKdca5wa#19>qQgEXGr-3_fk0~lEP zTj^K@rYpfzbLhSoIVa4J5bI`H=3pbV`h`Pgb#6a1L2C)Li-jNq4R5})8l2^3%-w}H zUC^*73wi1tI#W)?HjRuL_0`l8l`V|L!o)g^={k@AorIs?-`$OvGNz+jmKUmm6VYxF zh2%2%k}0b)`KH3da{c0w8>E3wD)uPi~td8)9`CGXGPT+NZWoY&Cy!qrfu+~|#1OdWb} zPW)>cjT#+tDB1v+xZJP;o#h=R3iK-~F<6QXww0HQFkg$UESwCcFEB&mkwjv?O`9`e zQP<2d6dpz{w42X`Hmc@S2i9Uqte42taUp#o!pPc4v|o^7(l8ygs8#EOWM?p8mH-

t$1>E}CqVw;-rT`P2m7@v=o$!Xkr5a(&{lskhqDMmQ-j``gi>Oe$oQ8N zIb(N15Yr~bn$6&7SPU=Tnl&TNi+NMUk}g1Z)KMW1rP1zioZ}u7%Rrc5BdBgQi(rOc zBiC$xG9`(?8!vp|9;3P~7)V6tFV%iG94SsjE)2$(&58HI>#Nb@PelCe5O zYep50Q_6H|P;|8^{i>V$uXG>&hCe)Xn80&!y+-?`AVzlP)(GgBl{}gtkSbe2xZ#)@ z=$J;0fi{1`gz9Ny)2ThF4RYsW|2x2eRJLZt^$u{{3g0?4@6J+x034$obFB_SVk8iu zH?v8a`gr@cI)3g{VhY15u*r4}#suP)>=q^IpZ#gDk&%A7kW4i9=BO33>MF0{*mZ|mT<%O5 zZspEYqpL^Eeip?PSK91iG=o~9RhOLcXqA9O*&VuL@m9@`1&kv_#v*~$yoe6{aO#@8 zNl(%Hd|-!4!-^|NKi{E%xhR!-27<({iC7Wgr<-cN;9=D7-s&fM>o8iA!i*iIu`Fe2 zhiAKp+HwuMwR@#)=HtY(ISpDL9=4(O@R_GVTX(~n1>u_5i5nvW&=TK`^nj|Key^r8 z1v~?2P235}iE`7nb02{R&+XHu`NpZQ;}1u~Hh4FL&5+J!@Pdv6_%)ce*bCeXeP3EI zt*;NF7r(&Q@m>JBTsxn^wLsdEFPJyL5aTMPQ4^Fm`XZ+zg7gLbLKlJ;_Qk17 z3V=82BBn!%^ac4s4uTiv#ja}{fH&r%remD+<$Xp7f*0<^t&0|*J@O)?gO>CK@j?uu z9s0$ls{)`s`l6(xg7gLR!W5z%_Qj>k5}-Zm!hVAl!GrPP=|Z!K;KiK?!xQS^9pnIM z54%|IJjZ{Lyl4hrhi>z`AirpaXa{qn++6PXiR3~10NZsA)Shtx*5QcwivPgx%M1Mq zz8T@o`|V+SLkj+t_(9H>H|$Nl#b9IKFe^9l0SZ!gmD5u9#bABMb}J&HZK0bdBE!e) z(=*^Rp@-Os*yWC~a)_rI*+TNN$~^fTcc;t6ChD9!WsGE1oA5bWdgHlsV%cr$%_h3U z=7ZIpzUOSk%fF?*j(j+Z;_v>3hynlr%im3X|MV8|e~>u3zK2G^DE}9Uqv0Lm0QiIm zCJg=nU)>l%ywfISLq<$MK(OPDrn&KJmXVXQS#{BWeEq)dp65c`(cV$P{$6WVfxD!l zrRLn2kmIZCq?GN$9N^W3`PD;UgysBWjz^o%dF+#hUu_gGX+*^H0}?5Mr|iHz$`oeX zy43E=4|(3*ZK>my?*5D@FSwy?0z6)-(~Q|iTUk#5+>CoUa^B)=T@UCb@;D7r`g3}b z?S8+>1`+3%hKPHViPjh28yDIAg52FhJ`ev46#a~tscR3_A=*Gx6F{xVa;;boEsD(D zm*|N0lLFlb#lt5QJWqxF3KSb8PmO)che2c%mXI6EBe%AQc9NF1vTH{>$s_FhOGo?H z^fB9)4PV^#`A0C1t7|y>*QhaG)FY{#%WA6^V*=Kzal6;X8z=dJ_KC*?jyKVR@#7cM zG*6;m9wpb5*=y&JkM}QNcm&WyXpgK1K*WJyS09gGx zK$Xsll$}|~yb=N!!6wC%X;JYjV|`iHUHV>P4a%818;z8F)9I?DCFmH)+N35HD7ksq z>AG%-7DLDsB0K8OD-p34w&D~sdytPnO)TTY{3Ucnfp`fraUNx&C3mJ!wU}wN*VntM zW#u?Tw|-3yRPPdpgO-D-JZP%uDv-8dKVr2_6+3E*&<_6`PuiryCiu zjp)@|K%2wP!un+&n>NQ>3fujXCAHL9w$d^SB(ErVmCw)aQ)Y^S7K}0U_y5-2G#9R& zrh$`&vwB=DXV3vV*aM zDV25aI<{^Mi`xU$s;0J*L5mZeWR|F(v!JuXrS+i%+==bYw(coLT}*k+H94)#IVC@{ zfRYOeLBi5jTUQf%A)!rA%+5{^Rb|#&i%lhhm8YcFRoB-VvWtEe<B&dkL{hU#oew_Ry`GU#*c~nGyC}~NEDR+;8}a> zOOIzHm^U&x;i;AAitv_cCH)9CtnsE}Xd>cEnJwcvr#7XaRGyaJ>Ln zmm0l{tDRgfZ_xry#@B()Q9sxK`#J2%p$vXV}S!{GQRES~3QU)ANI_)JUa(fvNZ&T=4;KTVs z*_(Hhn{8GtWHYR}T#}`{Ou)>9vOj~;cl^QeZOlwP&77Q&tLtY!I1beVdD9|DO3~2) zjrhTOzZfhXptLMDE>#9>u#6&<6^)!pJw3J+#8qq&0sICY%rFxELGTwW)l)$T z_MRmawN6@0%;;UO4liXpBQ@M?=y!;NbM*t_pj9D2O8*1mkaC`Rhd4rux%vT%cRwJG z?%yGfFYCWU9QXeL;&^`#F3)-pCFDOlD|P5+9Ra{U77!YIN%cZfTVN( zcZh@kzd#&nl(4YgK<;(q77|%{MrQ(ZCVU`c@9&YY8OA1DdS?BMFQ0X&mrEQRKO_z- zq79(!cZuWEpiGR9-iO2i0^gxM=;gX=r5Shh13t&f++gx)#08_24GZ)`;`r(EpCt~+ z{@*2zp~Vj5)E{#YP@5RokY!*y(Uq@R{*#|7eH9y9ne3!jIryWzo;J~2qV+EcYaH=Y zp#}YCyppJMd?niG)=dA@wgisA%MbhV1)U>1whKNnjW6m$QO zIG(v*0sbX%Q2vh+hvUzNdmIk9c&wJK`Iqn+U#HX2X!P$oIYdJ!hQ>2=#uJgF9ISPM z#HbKPRle@^`fEiA> zM9iwJgqSyVFJcE0kKy%JaW_!wV~Rhv0v!>H(OM1p<&zglkjte^p?sr2ln|kR3gC;< z1_L3DCt)C_=|9R8H#R|?tS3IX%(tptgxII3G3Q~Wm}ds362qxD{oW&e#QueP?3+@E42dViQwb zjca^1r`8}sHoi*ZjN#;1_NlAtB0fG5Mq>nL9+F#0;e8HJt+J|yJ@E)d z9wJkUb9iE|(qh8$5QSf@q>Qn)rp`9g;LgI!SDqkAxR0Mm5jFnvrOE!0YDHFBfi|jV z_B?c%)G=%ACu*|^-b0kjDhqJ%SR}>QNP-UUm@F6@zpS!(_>6do0V!zeY;(Qh!BnFF z@d;7k8DE4zXb_TiXjn=V81onwJ)`a}w&LDI)E)E+o4A#3XUO_*Sd%PAOOFhr4do;| zX-o&_H^Jp$4Ad^XWR>p}$La^gF~Oivj2C@k`v=9*>%a;6%S-e2cZy@`9~8&1d(_Fw zpC}I6#ZfWmtOpYrgA$a!!eumwc)f(5jMQA8clC|3>$NOENq~PSiG-8-cI(sSe@ZaN zSlYd@=sR1)otY?~pc&yRk)<&kua6j)4EUQdRVx8lHv5)wlc1rBcj!l*czHd}-c<^*diY>KW{m zO-?7{qm@Rp$c1Z7Ctm)~$YZ_7utL!)ADdqESn;a94L+9drDL5ZBNpGDW(F;ilb!Jw zn>+g_um+OUmE=GxvRR=|QMsJzxW=OUF`Y~ESnW;~Wo}tMERNUTERO4cw>Z%LY;gd* zf=>}y-^kejD>gXoZR90dl+n?#ErWXmgvNe*Rt`nmM3+pzJ2I}enP)0E4YQe#<}fhr7;RZ|OpJ(PlokUCz1P0d&`bX)TAzl*%9 zlzJ}Ba+h=!XqoQ5P$<&fxZX+_vdx$Azbm{;#O~s-8RCzX#Bk%GWnmkG`VHea^Z39x z0`EUC4kF;t-!KkV)vq|={T~>I6VdM&2j&uu`A@wYNnFxSeC!KcbLfHJFpkFi;)QqU zW4=$@ib3dEb0o8U!qh6!BH;t$FnQj2qMlz3UU%1!i*8~*!>OzYgSn>x3^;7Ae8)H* z4Bs)1`}33!jAO0G;prXYfL;9!<8W32SWk;uX2fysu$m7tz(g1h_$iu<0!M@_KtP){ zCGU7<8ZdykwWm_$(#Ku5dNQ9rk#47PsnLT*zsG{TgzS&391a{?BxMt{!fFNPtYG#f zB-}~PiH?aQc4SM>G=~3I5V7yt5oD$=ypT=rl1O&>TXpx(8Ob4O9al__U1CHWPsUF z#S)q5OUjgEZ*1u26FMJXGcS2)t_?%TMnbNBQp>heq}98pra7 z#!>YTjic~)jU%dkFS4v(V68VP!@UZKpdp&}C1b@4qGsFgjcot2J)~agZM}T4rx8>R z&5TWhtx#6!*eVK2nB6xq9_Qw#cd7-$EdsT>t|!$z$nowGqmjnv`JfYcJyn4qLcbaA zrS*tuXDd4+@Fl!L2^SSu zDxQLyz5A5xrkNrLLddjp&BPnDfKrj02;DT04-Zeia$rI1k)cDYC@6MF1DYf`Jw;|q;o}CI!;$}7gLml z=0N22U}QbEPH|#b2szYajZ+8*k0_ce+XW|ol3>gM2u+d-E^WMkI68(dCt9yZ4OXI- zB0bTBYy)V6Q!cog-Fbe>ODWImq{6{_Oy=Pc>X`i~c<#slB;*dV5!F=Ab=F#G<1mNN)CB!$1$d|s_0Jhy@);!j_K22kNM6=r<*`aBu6lf^E; zlpy{%;Tui9o_vumGQK@}12}})8u)~!eoLGEN}}XWcJx7V$h=jT@c2I|soz@9v>z3p z^Zzm}f0~zh^DlXom}%cF_Qbk9Z#Y^P{N-BybT9MfRnmrdi`R5ynDa`c^oxAP^Q4$J z=t)Zbwm`;nQ9;Z5NlN3^Rr)Qdqz(KwqxlG?@U2S$F6UKD=@;^h=ljt>Z?&3_LS){; zN<8R~+Vhm8-_nZTaBq1hN+f?p6ut#%+8%j+`$b#+bX@orw`O(p;c(D+ynXqV@vd>` ze`p+}t$u%K95Q+$yW1Zchw!_`!S5XLu5l>-RpVg!L*oc|*EnQ;*Ek%d|Ij$bCz}7E zaac^@+W!}gqwx=oL;81(L-22C93pMSt^bq8vHYQNB>Yw5_*DH*jYIqYpm9jPYaFzH zXdDB7SL2ZVL*qdHr^XTgXN|-C$DcHgtpDd4$K>DAIKF;p9Gm~pIJ`bI4x~Rc4vT+j z9Qyo2F91C!x$hds)SomC&3BE%`Ca3n{fox2Dj;abI5wkJ7;KT}XNQ$0iYMcupjw?q zqBU6a2!2pJZKEeB#Me)#O0oV%E|paqSo=1i&6B)MB4o z`{k?s(h1e))lcM(P1qJyIf7N@E*#G0)au^~Q@K3>3>e`8Yk<=&h{|&jy(>SHEWQqS zFRxZsyGpmsgRmx~WB{=C-->uW8kJYFj_zh)+m75(z=_{THMU&8h>#(Sa0h|W2L(ub zJp7W#W|$}Tj*-~924f8>79o>~aYbyV590nD(b_H|zn?5Hsu#1sI!HYAf@%c={psb3 zqYyb5UMtP}OtRR#znxiFs!)pfX)yt_F9N}B5aEKir2UHiyw_7h%*W&xO; z?W87$CXwwWdYTnkD|8p4V8>8up)jqNe1Y)z)D*pHeFK1R%nGn)V|&X6PZQWpjCoUg zIeeYm$%|m)Y5j-Q>o)i%9^U~^xYaK~ z-+e7XYAJo+_mTygVx zFLu!{>uuCYHe7+``4af7*2nrU_>7n(t$9%M2(7rHBDMtq9t@U7`>%C?`Q|5nxdDoL z96bATJh)FhDQJ3oaNvaJJP6dffVh(LzfWySVt9`wEQC*NKsk}??Z{w6TrtFQF~tNt z5c6Q<+XSDAQ$G$9tVc`3K`2&$-XIFKrE{H6ZSGu0^$X<<_HYU-}Gz?h&(y5 zFw~)y7s8`hyEo2$u)AS`R$(c-;2J%n{-chg7%?Ea27tS6fb)ie{~~k}x-ZV+ zM1yuoC~z{|7}^XkR*~ar1%9auT!wZ*)#eSi-TY|f0ZBhzL+3_+O8@hL30fG2T zI$s02(UD@B=4;;@0S`)^Y~sb?(72?)nRU!yj_$sLj@`?_&+mu@*3SL7~HgmF3i*7`N_mgxN}uo zF(<^J-w5ena*FVmzpw5^^wN=;XB+@y^U~S2o59Ut8C_u!Jv;HDF(x=^`}-p8D~Os= zy%paRsP!7$>i43!AvcWY9deDMD2-Wd1!JrfXRDFdX@kfGasAXWN(lyDYU~cyt36fz zo~!Lvej0dmB?tyFH2P{SmgU7kOEpHx(+8#|iq#yhx=@6Y8NaFaf)C9x>Q`9ih_l}& z-Yy5+1$wN)|z5ygK5iz+@VfhQ9%Jrbcp*o60v|~LR4ui*QV5gS*HO6z!gTaM>RRX z)(L^7*efE>f+w7hE(aYi0?Cnnb%bn!+l`PLmdQOPVJlS)6h6)O zp>cfulg6>|KWH2Yf6+J&e%Cmfjh-a`ta0T0rg5O(?S1;Y8V6WI0PdE;&F6}IvUiPR z-1Kj29M^wa<3RqOH4YkXihtKQ%>RFB9PS?)2kajj2T>c_;{UF3#9RF*jU(cMMA)20 zu%#x=qc>qv&5eEPfU@IW^~;TkfX4iW)mx_b4!GNtMUy`mF#?}mbOpW&KIhSw>P4>| zKCI}P2GLLSa4yJ{j^t>!Z@?=gkV}E+7gQjFr#FHfo*ekjoS{NL3MugwMRRR4aH5sJ zr2gn)J^c1#f|DJ5o)fuwv zPq&30VkLJ3_IXWw^B^J4WlFb_^aq;T5D(4sJ7AFg2R=4vFtAO|IF_eh=nz_it#AP29&rS8 za`fsZI}meYwYhP%?(&FU+j)k+S|1m>E@()0{PETeUWz9me*rIfK2CwJ8B}vGp$Z@s zG?JFE_$3yort_1I4@}P?%L|jy*Q4C=9QzyBT`=z0T+2d6UOW%02=Cm4Ga)Y7lB=hH z!yI8oVwMF7)(%cFvkPR6-W2I8N-JD4%_|fNaj)qN1ls0e;ND|y^Jk$$=_4dKUhrb| z!!~FzdPzA3hKASxqqK#&7!%VHz?QxP|K=hdFffo-ipJz5S!PLAMb&fi=L6EktrW+J z@6FCo4o+Zca%o%B(fq2xQlR-)X%!fzT(c~}`FRg03Iu!Yvpfd7%lgsv06g=PAvYvo z-%go8#4bML^hI^AaJ;nj2Ob=s@kU}E}?LuCvU|)s=?TTJ{-+#lHh&}6lwoi2J(qB$tUlw7H zqIfqto$EprhqNv`&bdVjE>LsZd)?4yuN61JEET$!d!#zwMz^4R@d#ynXyw_V@eiDO zfwgjJ$a7~548Z&&u1Q-$am)K9vx!_sotZc7ZeKI*X`A+GUA-D8=EzuWJ=REBQ||Ouw;~MRF;|0h(|v`bfn-^c2rkXM8+e0MM#zr`c*zz zl+xOwP8uZbTfZzNbq-5ytsL$;Rm`s123Joib5p`^8i(;I`zgjhG!E{>-qxc=HSYcy z+X|O90;#as>5BBcBX$LDpd)rQ?g-iOoLSp8m$|opTc7g2B;}vGE`I*I>r?*C<@hL0 z;??nJ`UD05kp1p*{Oz)~_v8Gdrubh%N12kTBbE}%s*=a=LI<8mvVUxTkXeCDx_O|4 z?68Auv%^Ub0ReSSXkHa}5fhQYH|wqvY1}-&_;^5&p`0&2WHlvJRhy+z@g6$1@NV!f z;&?l@QYYiMqDgR7>gJnl$9V43UC*6QFn;~gI)B0F@Nr`GLQ)Rj=2t%a5mthU8=;H- z2wR)oQQ2KQEE|<4RlQTSLq_-G$1GyWJmNxxf?`FDi%*_ZZxvdG!674;TYSLy$+rU%;lbc|-l08@1HU>}kJd;~1kXBy}NBZ;y49@tm)7NfR`<8({OXCL? z%NHCR+QWzP@bklmw(tb|moNQr_TraIcqA9PE!o?t{uxFOMgAEO1MK6}O>IedFo5Hl zR3P!R-^Dq?cf)oi)(sVYhKRj(=eH9^rry<*8|E>lAL=RfF?Iu9I=e2?`$QW;h|eSm z+4GT&|!tM5x)_jVW*{4?6E18Ff;#BR6T<`-|B-B^aWJFK1Cx3TrXb+56|7 zKE#H)b=r7WF%X-27j`%#qr@K2of6gZu#rzhV>W!A;Mm(MWNOMc@8?jXpi*4}v89&^ zOm(O+NG~_3Desv3-b;!HCvLdPmnGm~k!#*$&7pQPy=xUZI;wR+HBIZxI@Q=~m*>$x z+L3!<#%#-uO532o|7}C`DE#GgaRs|O#kMa&oCXR27v+|?A?!~3wRx{J(#`)jms-5dHNSpDbqqjy1p(qLRx;m)a zY^!-nK`pjn2)84l&`?n@?wAOF!c?nVAXkx~R8j8~kIc0O6%|rb9*;02pgSRXeoqdS zjqv(;!O}~>#~t^$lhwrzm9G@mm`bc5r39`0BtfF5?QET2UR5sXwImg_h zyAkma(=o|u+@1_PLSu6PJk}x=Hu6}M<>8em@_PSmxva%FZ#5fUrf9tJ+?*+Gq2T>o zrM`$m8qJTm4JK=38y5|Ffm%`?&65y@*i14L1urQfT;Aj$?Hd+JnyC5&$C=p8Vf~CB zkxhqPF^F^3Yv}AuS!=1Ee7M@}l41@G#cha-nI9{R)?3lgkzy&();g;4Pcbv#oBgCK ze>G>n)Ye_4$Xe}K`ZbbJ_~B4KO!Zb5;(p?O72;{_q(_pJ3!F5hjek~IL%{5L!O6k*#NDp_FCo$X}7{uwtXWzwzR7@myoP) zg=ixRUeD`Dlesv9UkSVwv72mwYZcax^r%YBzC`rjn5ytEu;SJ1`{crzf2oAs_rD8{kiV~J0C9^=X{67w93oIuVFFN$L$eFm2&>HI}x^(s-dnLmFvxa_Jj z+GQ7k~;djF)KsW6bn|Dv)2&J zdP}1xiZiJ1>|1y#EYFYQ89u2gwM;+wwn{$|7X~F*Ij&D43v_}mzQWe;rif=T_p9Y! zD}Y3M4SEaS>!$YJy$*^0ivjx21M7d4JIdZ^2PArUcZ=jbpFBKr>UCsdSU;dPd}{y& z6S+@O*|Ovc6_Y3Biw&y_l*>>@V7i6Yi?+P0SdI!)`-jq`Q%g)BQ=~maC6%mW)L|J% zF@1Cmp^nMd;X>AeVPO_DB+dI`poo6;qL6xwOXJgG+*`n>CYqdNA9{R=* zLCuto^zc&5azH*gS|wEZxiTN~;Lbe2FEh){yrR0y|1~0RCeseD-XntMT@axCyAkm( z&LiwEoQJS5`8svRd%>v97JN?@N~(HbY%!QiARbk&TVsQmD$s*Z z$9Q~da>9YTWj`ZbIv~RNt!;PH6NE_%y0whg)n2|6g8dA-2mVpP+Yp!HKo~{Dfm2ii zgn5FM(|9Mwoi#z}px^ZJg(T<`Ai8ay@wqlLoapujKck~l$H>qoble6Crzqu$SQPhy zIh)+7N0p6L2Xq$^*!%gIgPz|S6U!1QL^nEhNw1^qDdXHW?p4w8O%q#Yl5!wg=4uq_ zC|Iak;OWbwE6SG1#$8@6UYFH`TyF}|+h5KIVd0=1^E543U5@mV0{V}6YJnXlRa{y) z5fXYQ+a5$bi22pHV+;{#*BdJ=bs9UK)O(^yFcRswC@~X^&7CymLO#uy27bM0aHKzG z7}>~Y!JM8^d3UL?-=1pyD|`sdH09nS=ARk=ACd;`2fOjx&g8#S7>dS`5As+`W_}T zEXq$0&s}vsC*zbr_&o261|o(H?xwvlaJy#>W8->6l7~!wgm(& zE{Q&t%FgKQ?Ct_;6?lrxV!NOtjD;ZLA17KjiAK~}N5{Q(C7HBF&(Go!%Av@(!;euY ze2}QU?Sl#7*)OF~VbO9TB6Jh|Q}bZXif$qT+Akcx?h8vZv}@cqY-O@X5p)iW{(euB zSlZn7n$0{by%8}XoEr1z@3};1YY<3|G5fEMo$I$2QYEa=MfE>}MuZOtU{Z_&x}f}5 zOR_F0qU{-FtB#D=&0Tb$CAQ+2XFOb|M8soS*oD6sU8S_AyKp>h9=@S6o|e}j@K@;v z&_wQw#!T}4Ix2ODl&3!dX4#^s{HDgaao)AICe|GXWx}OBb;a{mxp+9-VTgfl5Sgl; zjOxYoB{AtcY9sv~nevyY2NE4abc6mP_K}z`(aB=kUYX)m!c_t?qG5R$@%<|(rIJHv z)5=5-Lx#!)uAo?d8iqc)Z}5$p&-T3#H3#{>?)mK5biL-QW8#PWj$*W)I_S zh?O{F*FIFI!wMdJ|JnTVY+{q7^f>m)#>Z!J5E--%6$rTC0^< zSJ9he#x~QlA*cEI%Xr5R-zOe2-9;BQAr{l)@ES3`g_)}+U)8sbNCQVl#7376bVlZ% z-=`Oor)pN+h3X*6s0)&G&4J3z6Lp*KCVmw%#^F`jAjX!a(_g8MMOC%|YH8X=)Y@a} zw&s^a9M*4?SyL+w!yxzd+sYAt7a-ciNCTdE1Z)Zmr7T_Y0Md3$V!Sq0u9dXKUUh&O zwrheB!WukOftZ3{Y+a^w<%YN%+`&N#!Zs=ha25wW#TL70^Y&}mw?alP86$#S;^ z`Kd-x1jAlVt!-VswHXWqGR=JDQo*jx21SShU-nqa7Uws zI^_}HcuM$Ev3)sYj4_jP(ySvZGRtq~lu|5=Wwt}JI2iuE_PfF$lg^9-PyLT1_#x2y zFw-dP&G57f0f7-;<%iWk_QIeekj-Kkx+cHfa@zl#_L(Dtj)jl)`DA99mSeT~S#ii4 zV%6@MDr(k0X;$h$MbaDoa3yW<(GNqE!O^UPVgbXwqBBSX4SASUu`nAAZW2XC!sC!B z*03mam?FI&1*O@V^H%V@T1k{*DXG38`j&#@<#{H@A7?UG-fq(YMd{Kz*y3iuNv2oK zNu~FfQ**G=g*(J(@056AQ@TB3c^vvA(ssOVL!WQ?7T80U?_6-g%{B;iLgk6TSn|xN zud4tflA49gCDFSeis>)^g3e1|T7-`TT7_z}RX+w&wk5eD$ZWUz9Imr{TxA~8;tZop z;SrosWc7967k0b!rPxdG*7mNWpsR=)Epzy!43Vz%0HOy@@dL9*PWBILl=j`(^My*) zPp6vH30PSUcKn~8gu;(7lzPuE!BCJA<*SgIWQz!gVTg9{ya`9%e!!DEoqk>V^27Z*A?muG;vPuS*W%(MUFYLZ?`P6SNZYqu@0I!#AnFl67ci3 z6fP&Iy3i0rdUIZ7C41wX>XiFrFEKrf^0(?*N}B_pW^4o1zxfEPKH+K>s2WZ}|F-ZU?8mezm8SZLYmpG>Jt?*u`qwWVeV#CqJZ4yaZIy*zMo+Vzr`KG5;P0u6b+ zIP;nB(!sc>l9F)p6G#k$!N5;Lu+xR{C44qoB0EL&RkDUhtAdGa7c_V3fI}tzSjUO; zG=3+v)+I{OxcwNH{;phy?+xBFiL`Z1>L%~IdO3i|I!>j~vPR0^awXI1DkzY2wvu>b z?V-H@Fa=A?(DjoHIkz>bue?SN2>J{N((?^cpyV*istAFqh$_3>i`UgE&u~1l8EwB$vq=uFFVX1fL5(Q(}kpudO^6#4Vv;~%=^aKSe&it7h@BtQCbq#8CKCz~n{N#aIv62+h?_S}Ct{LE!4%k))CPTprA(|V z)LfgZA^LN8pw)}{hH5TXvO?ww=TasNQr?S;2piFbB=H8iyQ?7sw<6MxXL^iCLf8yC z*dFO)4nAc*W2RbON4}NE5om}UH7VROy_1^t$4~Vi*3cn?H^dk-5_{PAKDe1}z28Z= zd;lw%vR%I$SAr-*2YA!5<~q}#-Da=+ei{&2*L@Da%rPmH9?!)fQn1A|(yOWd^8> zo_1CRy|@y6fms7aTIRYuEp9Fqr-)3nFM;bO%H+|*9ma~Pcpj9p2M8x9R=m0b&1OB6 za6av`3WH>sFPZL=Dw+tJ?KDh3sI&lV z{f2z55YGZb=L(9R-8S~$Kde0Tk6W&P;_BALgRyg8>CJ}&yH{Uvy!?^%s7_(5MR((} z?f4Q3My@1cWfmqsxWRyUmd?ONgahTDS0%qS%9R3X+f_hLP@;=-c@vAJQi_(TYsg@@ zfG5NOrI)Kvd>eotQH$U;d+rCB8wBfpVPt2;##+3<^xa4td3-27VXR|A@+x9cz5sfS z7&U6dNfeSwPuYX|M7-a!F>6&3-8+rkUSC=3VYnd;B!B@T4kd`rrz?_kGbx>Nxbn^t zk^esMhyf{!Bc?Hz5jJirUabhl*sebg&*Kv)?YM~MW$fKkzl#Oor6}sQ^5g2kG+$X5 zsXCgPxtVT3Sb$T{MEg@Edb+yTh%E-aUGbK1OoeUrF-cdrQ!*q!*zqZiI`sBJAQ$Z$ zA2U}IwrBh+tC(R3jS^6=91vxwjM?OouT_9fN&CdEf-=H>FS|z;CVkwUGOTzx`iLoZ3@!9r0a;o0(xxW`Z62=yGe~KP? zQ`=>EcnXttKQ;x9x{L4eep-Gaw$lzaA} z9stqm-qVhRI(w1`;-jUdF~(gnAWqP7NIkAyA<55`3z!RE50vlqo!l#EB99B(Xmhj= zz*Eya>bV^pTw5nFppQ7k$IK|T1UUhBZH}|t2&t8x+)I%BhR){=iAIOqz2u1wsvNTN z-1hI@akehks}6m=Jd}kgl7y*Ow!~oA*)QL7^uf~ePC6WYHmaCq5kVrb*JZO>^_kCE z>X%N0eF`a8Z}ZR+QYZ1h+kx>qfq4yUHgoqYrrQnTC#MRMMc?JryJ5#*HIQ0mp9%zg zJr9Rgi3HL$5RH(`WV2X|narvyc#;^aIrp_+&6$kTq?=JGxsCxAb$nEJmYnv?1`W1r zZo?B`koA%ZpK@BTL9BfzMp|iCpPZcUy`4@fXm{61^qZ&Zg_0rrzhL)t1TAd?RoS%c z6=t=Mi?ty^^Dj3R-8jS-?6(y)O0@XJr0$rKK%XQp@OKM*B7;_EwFY99Sm{zCO@3JF zVO=uGGT&mklUVsGnECX^N@MlED0|1~N~3N|xGJgGwr!ggS8UtniEZ1qZQHhOJE=JN za_@b+`+e{2zTMv#`#k^FIA@HrpS{;yYpywWyW^h@_*XSgZjl%e*1=bHnWo6jxn%Z< z=xQF195!tWac62(O!dZ4#Qx$eajR8H?*4_t<#ZZYpvJr6dwkSQ9#2f|BnHEDFXM(< zlo&Rl4)W!&+9oR5Z9NN&@a_rs1zFHf?K9Vr(k}RTPxNk*p>C-g4Zgk-u zR23v#ijkm?;NWCk84(i=E^P~CIok;uf+R0tRa*Z;qj8>atKx#_}MnK%5tJWBr`DmP4Y-_W1wAD2d~giIela^Un0rHt@E zGZkA>q*je?FQk;17(F_J^{8x+d?5}a4#Ou4+UF1Ngxe-zdi+qWiA)ZYqjr;`Y@KVo zADHZHw&pt#1cweX^oo<}PodMTEQehNkB#=8#iKD0TOGL>j0Zs(*cuN*&?xm-EAkNK zESMAszb4g#b3LdYgrcrm2(wTrbNYc_&Y%W$g;==V%!ahMtH_ob&jB7Z*tuzqEQEqi zIfwN(Ttq>BL;wp`1$$akqZ^ko-Kyi2J}*Nt#K;tNJ3jQ_*f75NrZ`+d1K>v;dpG(h z@YP@vu5aYATMzTh=+Z@}lR&d}l~8xg`NZ~E9y4aECoyerbt+Ssp=P&#a+g$o(S~wW z@TB#Txpnhrg|ojWhX46c0U%iLqwG|8vIn0}!aA)@SROYpQ8A)muBgF(GcZ9SN0KDz z=`)FHMQ5atxJ*%bsn_ZJrdfE`7FmNBcRrhIefoSG zTK`cs&|Pka!dt!HOOIPNgmz<#LWT#iFNYHyc^>dLPzPEn>NqtdgVe`@&W;2`)=Y$=7lBm0@i|C@5q?*HCx~0L{ zUb-#wz==I75#u1uUp9QmV6F}iI;E7<6B)Ksc z3haI{?1(36Iqf0I`--f_3F4o);C09>M`Pa>Mi3Ud0Zokw z?A49YQ&@E*57_M5UBc6eESTn?I83$4c8}P|%8WvyyuS+dEHafKUt{D~k{4ukKA{~P z7VI~E)wa-Bwh6+}6edmNCd9(Z!}RZBl)}9*0x{zKWjK*unm7}sP55=jWKweA}u76vTJ{+1fiGW_5$cC)qDC-n5O)gUGh@>_Jwi7qZ;rnWk@$Q&0= z6r^yDA96TuZRE}?Tjk>&*Kqg)wGRg5#+_(afR{C4EcCJgifIk)UM$Z+=A2a7Zgv!t zDoH86u16(yUur!o$Cl7Igu&pr6dBUh@2uZyzG7mOQQ4#@ulh11F3#}Fl~#ro5qy4{ z%2SZ=k^y{ECUMdKuOX|RmGmF$|MCI~tg5 zIs?YKrr}W*6L#Sr?<4$dZl-~$CNjY3c9p&`EkivbW>rIOz$ zoR-2i&2>&*YdtbI^YmWd>Nn4UzB+rXcf#G7r!~Y)08>TbwVvu53*hcv8<>rV==i=i zExRnXe8_s=?cFC#T1r!z zcD=QZxs>sNc_p1LzgAeCR^*zg@2ITaELHZ@_cBPPnUA~}P`?oyw=Cy5es%ZMEmx6Y zH0@sW>$mpS1qGp)Myi}igix;o@G6dhntOK;jDy{p<*&m4OmXFC7Jca=h@&z_-6M$V zu(&og3&dh!ntGcpUFiy|tZX38^2?1Nl*_7uzvndCMnB`#1?~us3dVO2)Qi#$iV92} zhn+s;5J&UqK~gU}Le;I$%r`OGQmXIDb9MziV(8Gkh)P8RZWX&{&qwPv>O=Q`v^`5@ zJ#@Rjbhes$LY;AR!FpnQr!c|g0NE>5MB)UahW{e$MFN+~Cv<{LY$x0e@xoS`FNqRH z6#_Ks53Ci*Az5ULT*{H$x_yf?)_49Q(2NLF?Y&Mk6-H9d$FP|3tJI8abE|>*@WF(E z?=BKyvqkO^Wv_y?#mv}IhzhcP(j9ss(V)_=&OZvNZkCs7qIwBx?~Ugh`2xvU?ft@X zHXv({G%8$75^uNkn&SlNK#rj1^aW>8Y{(pN{n_Ea z)AV<~#5%iIUyYXSp{emu=b>0|HM&<94zv`F3 zn&=`iY?bUa0{c^SA+D~jA?+(*LJYG?&B9aJzdyKUByj8^f#k2R9()({!JB)QSroOC zPtVUD0W^8E`H{4op(MW(Ph;~ceGdx2)H6pyaa=P~;e5j51Ii+)a z9b%0TGgz(Fy%ykvcz|J(#7LkHfRaWi!y@d2eFimad23jSmG}*b;eojwA*iQ7luXMI zo`1yB1L$ZaFNoVaekP9nxc!0mOIv+Q5(V**WUtK0crx(!Kmv|meXXpub>G806!3tD zpj;pI?JZ4jNw5vX5Hc^^AbC53k~YP*1%^55JtlWG%3FzGf{vmrt{j*1j2{-qR%ju0 zpr1dc#}AmU?BR$8md~MFw3FVDkwcwgyr}QpdN$d{X-Me`ppAbbQ`f-Us zVA}38oHFCW`*^aRRE!_J=*Y{-y#Vh%hgW!=Y#d9SA8A9qbQqFzVagzfwK{HmhBnH% zt|D#hYvS*C3kQeZBb1p{SR@TUgYa35!NQ0)ln6I6t&UW9NV)aB^=^1T~qMv5Uej#3?4MQhrAWc(iAjZ>dSwX5J|8#a!;XZ&3S<||JElsuW! zn80&It{+Xgokq!?LR}NApgqZZ@wBipdcPMv#AMpuz0Zsapw9k%0Z$p7dl_&Cm{*1S+)mi!v~Zrb zv@hZ0#zeV1m6cA*aE7>**hnjZ9;OT)*D#cKApA{FyDXai7SG6+TX}#kv&$@#w;SO0 zUMC8oKwHoTbbMG(6tIp#g!YyYoT)Zmu#M^$M%v&Hg}4uKVRL@sq=l}F`^9!<;Ni@Pb?f3T2{Z}3azsrHKH1;Lwk(PlE& zExG!&>#i&i{3>0dF>3nmu#{qPlJeF!usG+sjO$B^cdgn51}d5|76d=ilCQXj=Z5cJ zQ{jK^a^w96N#g(5Zf0WmFPJAw_C<^L8}C$t{P;one-HmR(8KT_s3%jw!Upj-a%X?N zZmw=6okyc`AgkT{!T?-ksIGv3yuaUTZi;1)kx%J3bSlnG_e(F{PBh~d2C6Ks@TQ@Y zlk`>R@dlH#_xt-_oFCeKc8KDC*a>6I6|y0t7u$bnqf7(KP#z_4;SBoiT)f9cl``eD zT`Rg&lQN$(eBWj;NF$v_ZFF4MC3(O_sgU5rnlDQ9!uV%*u)Y@&l>&{+WH)Uq>N}Q| z1X}(`V$$R>)Ir!SR%S1Oq0y0;zWIBJG&xCG^9y0&xTtGOVPQGrib|tDeP83SybY$z z8o+>vreuh{@~Lu-yTmn0l=(QbD?=MQ&f|NJVGPxQ?0xgy*T9R1U3KZ3j{ zpK4?7fG#Z@1$KBtPgB$V+y3-hx~rh1*{loh=^aev32o&ivZN*FHNNQtjv*~-Y`X7gn?&%$Qki0@0bKao7S(Al>= z%*{|ruHmdFSg zto&1g10Qw9nX_4*Z)9MV3x}>TyyU2nyTgvmtNc*VwSBE|Tu~{6lb zE~UduQkoA}7%nSBSNiWKp&wcP``JE%hrm$r!G+G)MYZ9Z8OPfwIIq#pyueN>_^0~P zmk92(h%F~1us0Q5cI>Lj;l#G^%@dY}0|EJe?brcz~gLWjjtADovf*&dx89^O8jtGZeBmx6Iov%URs!`(*dx zzwD=Z8EPZduVh@$$rla^PFs{mckM+*cdhx#B6_w6imA`$x1U7Rr}nhz4}|DQ5J2xm(oiVSF+#@&e-zcS5uK|`u1cN*V$Rv zwfA6^vCt}MZw_Wu4kKe+cULr^;YhHDe;$e*;m3eMK^7K9qJrKAC1KMGPsf&?-RUMFqBl)&NuF;F8742A1JA8q}GJF zWOA3GB~8Mo3O18@&XBRo>Z#HvQ7ZG|$H%J3k`L*eE_tTl>Xk)qlA9~#%-solT9g1G z)$-L!k}~8MmVENLE3ueqi>fNJu-=}KLFIY;opGc%{Ee;kWu%Eiy?KdUr{Wgk?h`)3 zyAopZCzgEWo#VBACDe#Bfec*U!n|yywz{$BQ-kq~D$x&+e+Bvt((H9xQjnGz(~7Lr za2vxC+ONduR3Q2y*f(w@X{B|1CXf_J0NSr*d29SbJ#5I@8liA_+!8+zdlH~A$*IPy zj`a2;CD5ya=qzX~=2={pY_$}^YWz8TqgjbawB%~S3#lDJkd%X3%L?U_`UNVzS`row ztxs(%gOWKV;W-1fwgf^)f=H0hc1)zecm$ylCHFGUll-R3MdM3kX}qG>R`tE5b1d0c z<=$F&D0i`RV-f=HxdEdxWb3io%MenDOPejfa4qVbcwFx6~X|?m4G0?XS5z$G* zU|%7K*|{@Kvdpow0CmCybP)1-!>xsnYgbUNW}VV?ZYyaM45%bX;8=krxF3pdOoP$3 zOq!q|a)ySS*_kTD1>1r75xB!6e*r^OX|uf>fGoXZ@Pg#YEt z+v;aFB(Bk5W5a4abTdNK+oy1~3q%U88 z(odvqxt0|w3Ok7mY&!PlmD|x%0R~-ECXI?K| zeK4=B0q@=JQeuZD34?(s6Nl9W8YfQO`krQ zO*okqW0D7bD~jR_3(6e%TAUtPnPA;JZr9hOXd&@WH zMUb;?&sC62K%lSHV`*cu2nvhkC8d}NW@REBTZ&TVsijHfC=aKLu4LLNBT^XybNaHn!gWb7bFj#Q*Pt%p(y>K8h-~FAOkJ6M=Zo;d|+5t8c zS$x^JWZ|J&<3erp(VMGfoY1OV1n8Ys7T06ww_$}Wnm?zE69t|kfa;}jvt@VEX>J&U zLK2=8IWPs67)LS+{eJ&>GVm^D1l@x$5IDt*JL$4xkD;^L+Rw) zlZI=BF{#mV{(TH(U+({&M+twyZgHDXG=b|}_aU82j{OQqoDY1W)<%$6RZ}m^O}RfE zJ8ts}W^!`sV9%8j{R&(wgn_W$iEN9+xOD_4B*jR>5vf3lsWl0IjhFZ4S7!>m9OIf zbJv=?-`dT0NZz}9yNzhdFAmd_keQxU z9IV|&Qi{aXCLGZ-zMth#sTKZO+P#*g&6Z)Y&XXa}{|Hf*I*&_qa)Bz%Qb zhkm$FEC=FR49Yx%wiX%aajH7?{`qlj%wr=U7A*&SA$!kVK4s6^u~XsOlmjYk5yI%> z){^T)Ikiu-hrqvj8h;JY zYiS*9ubVEn+d^HD;PVA&*o9GL@3qcb=5zu#0(&PvR-bTfZtBsnM?(WicmICPA}ou;3}G>T_p zyT3DsfM5DN&??$P^AMAs7d=aecxM&i^D&@4Fl`IbSJOYKS30nU0Z>-nXufwPTiU^) zM!#N|x&Zunc`1s-x4oCb!g-Z==L}gkjRzBVJWz&hRsyd);5{C7&QvK|4z~=AvmEtF zl3F%501bsxNl0iPAA5Au$$0c?)vgB7kgc+*)Yf%*yeDqeRwxF*Dbc%U8#ncDKBQ9U zI2Y=v6`MpYX&L)#S1DoM#$>cc$iZ=Qvdq}avIq2FWz*7cXVdwriYqZESxCk*cF0gqj=YzJ*J{M+sqSn~WSqy+x#h5#Dx}9w zC&t#Bz^WuXnlj`FP?>#!jx(7XPy;O0y&l>X^xF$o3yW`hb?yNOZ2h2D#0tCAR9}Do zZbjF&yKShLGEH|W?2AcyqakGqohrYxdIif%Flt2V3NbFe#5tv?UL^%Zsei>#Y@XL% z&GEizVa_dHwxGFNQR8Xw%9cqdw^YWYinWar^lnPv-4!}H^v7EY^G#XbA}#EdGS(*_ z2gR+f-_Tk)#WDtPHl-ipx+FX8ecyC4C2wLn4Hwd_B#X)A8p#U<$dfyLUA(B0iDw3d z88Z9aNhOUJ4zzMLxrb91t3pi)tFYW}fgYRVWp@bGR7 zpBasGPY1dVG|jtOTP2_90?gt*#@*10DO`hAO9Kj)SIc%^GsqY zrt29!e9>a*^pUy(pkB7VEs$Njm8j~Y-`Q^L?W%_^NKriyxFu~YALuCFJd~bZ%C6>D zs^;t8-X+3H=_uqgbVwH&53lEZ5X!f%xpb$1Ww%#<6c8xPR?!SCv_VQ%E(B!fqw0{c zcKOnJ#M|@g1eNpZ6#v`W_Vnbfk~eBG7pnQw5Pqti-)7@ojoQ`ZNIIaQbo&UDd1JMA zKKO;@!E?j3Z=nI9qkgdV{0e*fh00!B0<7M+hJ%CY@i{wT*eAjkyk6i|%}9cX zV1x>@5eroncm}O0kKsq;hhv_3yVhE2NpDv(>E8|HWvusDv?}!Od&4j922IlunD@E69A!WXV~s$i+c29OU0K)G2`9O1 zF{C#3YZ5%srWu_5G4mV*JTQk$$W|D2N23Sl>*8+yW&|nyNpQ`(a_K{R(;TMln!Tmzn!n`{=k)45lj$gtnoT0$-LTe;=wUmIdj!#5*fN zww7PKVA-NQ7pS(7h1T|`wOqSM)FWlf`3zF+kU4seHUKVXE-lS(2yV2Ff4WiNUibBf zI45pcFkCLL=(J7msRZ+osmM-pk7&bO`mvcaN5~fgZ!S9H5*6pX;Jx}Q+=HQZ9$P?n zZfUmw%y6Ti5UIE51BiZiN9|+mCH$)v3p-y~*FY=%T)w&S-H(sciAG>(G4$OZLnNlm zm_kRKj4i+Sp^xmK#vhy?;GKa?+0vJrb4C|YG+}nC^fHulby<9g2Roz*3t~t|FzQ5d zU}?U4@aD8@2oY4wk@IZ7w^?4@C?*tpmhqQKx3fn%B=0W}wwG;MV4QZjgqoNUlHT`3 zC-#s*M-b|b`s}k+xxrV6(|Xq}jlUNIPR*$hE)2*>F_-K%ersCEIP-XqLBIj{GgJo} zAKmRATVT=EYq%-YlC&nVnoEP8p|yWsKz4$|xd2EPCUD+2ynn6i&it_IL;t3uTz!B3 zU(X+TBLgEdCnNj+IDZ0TCck~;;D=2t=2l*3)gN(?2MQl{dgBoS{NyWl3WIB`hYT&^ zDAKKPr~Kh|1VfRCo`oHEr>`bHO^${;I(T`2dmt`AYmj>Q`J=;bA3T^d@ljX?t(%*Xb=g|25fL1d63mT0X{QYceZqB@e z9s?Mri*^im+4C2+*;wJMqM;DfDn7g0fBsNhRwkjgDDkAg5E*^|RU6%9W>)Y<%< z3)qg`g+s%&V0yJr!Fisx75xj(5Dr$7but-`O=<)6X@1_@T7r2T9za?p$4DVfv zHhDWWmDG$jWpFQp>G}LIz z$UODRvQC+WnxY^sq-SJj1MZe$$*c0|>4n~7^JhXoFa(cMf(C*nOiXDsaVH*&B+GK+ z_4HMdQ754$ib?gqWs4P1!>ZMxc`+O?vw3Q@(5rxeAc=g}Lnye&q}WQVy0lCtDv2ay zl-&d4P*iJ-#-bdbO^|8#Uh2_6j;sPFOK4wJt$W$KBBL=inE5}`RmQ4`mU5g$N~4aK z6Uz}IM9Jy~EB8*RKQAa!l3Hdfs-aAjLKnYBPDt{bjMVE%m^ou_YA=wCW&in86}4%&z=y6 zv3tku?C8InRzq1=Mvx*&V}@Q#ZkB>-2TKA*M&%eiMBUs}rVZ?;9MDlk4NHF(Zam0F1;GQ7iE|_9`eR58~mH!XRj158kp@p^Wnu8}tr8|LKl7f?UBynLtH- zYI#`^7!@kfR!$x{2ReUr>}m|qUgleoZH{^Irps12w3(jp*TI@M$($T?J`G8f6CR}r0G zkPmH73|gv;ED9jD#rLZQD9SG0V#1z|>_kLiq;TTu6Zxe@J;|!{zj0EpaMBtm3@_vN z0bz^qp7|F{ZLQm8!@4^HYX&ufX_N7)vat?ySS3Qc4ksv8Vb0YUe!GoJz?jpwbK?LK z_ZVvPlUxoO+JFtNm>_^y8Ng zKMHz$1~0{(v-)y;CWM%1BLU6txTx=Y$z&q*RiBX6?E#TcUzhZ zKixhSCU*>67F{N5##m-k?y$i+cJ!jkF5&3Azs@8c2#zAvD^0~?!*{s43St|~*#DYy zW$Z+Ue!Txg+?gl_X0?Ah$M1e|TidQS$gt?5|7DlJ#ituVwIlS((eQ8$zA@RMh;=*T z5WyqNp2=~KMJU7Y2^HzbKEx0OKTL!jjrfVa)noSwY=RbY57DEQIgn1QP)?CS_`YN{iLz@F^0|?O?DQnl#t4`mN@nOZ z5S6P7+^4QZ*@HA8AuEGtnub3Q%y1&$nVfYplry|Vo#xt+!_yRI7{UXlonChtK5o6d zKM6a&VUm0gor%XS1E3{t70ubfUSH+RIm>4{l&<{x2-vzSB^6`Ia{bBUqg_<5C5dG9 zJ+hEP`s#l-XP-5Uwjcy`@XaDt#2COKb-3Sx2N|1I(-$40RKqKl_eC` zmC<>Y5m8tCZp0{v1LEX+hKP#-nJM6bd}CtxaRV{acmpfZ5r~-TB;#pck=jn`(rN2Y z{U(?x0JEo*;h#m)MaSZGHMLxVXdA;%+{bUcTK7-ue4oE;Q3laD?YM%tRIPu5U75F# z(NW#iVGet8$Bg&0-3CdxOR zq@21AGi1?iWuTg>)!#MkCgCW2w=$iKd6;-4kS6OKj+jojP|>N?)t2vZs}RJ36LAc- z#n7O+vbCGEm~1$;BTgcWG_I(55S36Z0*sE!Jy9V=N|`e!z)PS8Gbj)=nq0d(+Ko8R zhm?KerV{m+$PJ-~C7#2=AK>t0y3NoJsed|6)9t~J5KjBT(CkP2p( zFD6gFrnNw$NpafRM3qGxHL_>X^mRrYAEk^2)8H~zM$H>Nuky*!OJId2oRNgB(px1t zRk=>|kmReDY-EAj&kZpuWi&{9Zi!+ zV(Vndw^d6!XAh=h@hIH4@W{`HGU0G`6asiarFDhl!f0^TiJgw@#(^qa$p8)t4Y87< z;BI51&Qlg^{fjvvR}#rIbWarTM}KmU_N5aql`KA~?Eq4y$s<>foO>+@=v~WX+CM?` zp}#)hQ=a(<`cz69Ns00N;~se=Di27$XQ-YB-sW|8`l?tooC8ET+R|Y_i*txg!&gI=0>2o;@_UOqF0davey=V21num!L{cAi&o1!V zjAn?6Dyk6*lhZUKreGNDDGX_xaRuA_3Of8s#5j$V4rP=MDk-f{NGZ^ac;`WannNCX+>3p)K|KQpq)V?EFLg6`247Hio|aoi(Q(zt})`LP2=-mjwbBNI6P zltrsXwQu9)UBJmU<>Dx$RGoTxhctIX+At09oy?Xlhyu&S%a!UKM>?rySVo?np8#~04UNKk)>VB!9qJ(KfnrO7-Tl{E;jc8V zq&C>jDLu%9IM1`Ez$HtwQg3{8Vrag*K=S9#`6@gD?R&QuO2g7MSRzo%97`Tq7pN(o zvGeZXTIz(`>n+1yNNg?QL-7L(!;ljWVJPa6`=my7oauTfto^uKMh)U{U;=McxgWNs zI`fl}L7N@Dd|wS>w)Q%&X#WZn*w%I1aKFb^j=slMi2s{J^gI3hpJ!mCqME|IEb^!I z6A88Qs?bm29J4@hN~JJMlm_*gTG%lI)9VJkwShkhH=-{-Ow|4p?7VOJ*wa!1rG?;h zPaEGn=c$(|E3dDYTO@u+ECj&rA9Mn47=6|d#b4UoNZr|@48Z{Sd%2DtfdKAs!Y1M< zBfE+aBBTKc&}e1DkVB^hEv3>Dw?CsAMMcST&|8?z=%n@_`DLacg4O6lXobr3l2r>d zm3b9skCbeSmypvA;dlM6l?CO>n+MS0%jId#F6CuP%E}G$%FQmJ>8Bt9P!kqy#x(Q~ z19YrpHjK}VBC#oL_GwdWXNy+WUdSc-==nLytV#+<-CD)dlol*Ou@Y~D)+P~Gj@F5h zd+v*h zzc??7XAYfoLeuKrmDN&#PGULM_bfBlrk2dVB#_6=geyU8w)E0FRiX*iHyI%DTOjJU zU<^<}RL>66KX{+|jflJWH|I6T^!?gHG&~@d)Ys}`UOF|);2WrCiH&1^bxCJiI~Y}5 zP@h~Pcd~mS&iLq1_nVsA5Z&dUtFUX`;d*=?JF} z0@p)t9-Tj5Fo@BwvGGfmL){_M8Vz~SOQsi8MixRE1$L2!f7r<&(hn9H$R z+#DJnp}$o;LGEEP6jmp<^XWmz+s2Ifxz4xv3&nm>S18Vu`3Rae^tG2rtb1qOrZ>eb zP2HTFk{~qrIE>V4=MN#kCs}K!=7%(HZobmA+8Nnm0Jb%LaPH15N1Z;Aj853bY8bcZ z$mu!J^vYrM7tlYwU%qnk{|pcj|M7kq8CaUxIv6?FINBQ+{VO#5PZ4PU+X!<9oBt#{ z@*Q?droMy!ozuKR{jd46fBm9=4-@~6B^EL=)^oH3i0N4yTK*5bUzlj6fTe^y{KY1d zPK~vu|C5S$2FOaRW>(&cB}5+b4qjdYA4R<}*)Y`CsNa$`vy=`nWV1_lQ^|;Fd=as4 z!I$86bv20@e@V*JwX-q4dHhSP(CU4}j!8)IkKW%v*NUA`KRWch>6Y0AjH<)& z$M_0uR`X(*PB|NOBOdpKlJr#=Mv~olgAkg9iL}lUcY0o;eA{W&bFhRR-uLL%je=*spf~*-#&x=Ym#zAdlb%R=Sgo?hX ziV_xrCTZM9>z*BgP8Td=)@}(WWAa^XZ3~jEf>OU}6(W?vY*c|oda{yfo8`+enduFc z3tbA~!0NiXZ_uN8ljFl0?+dFfesma!1>|eWlNF2+MR%g_7}J;=6~>!`8TbR3b9x0& z?Gm;Y6Y#~Y8@G~WUqK+;V_IK52G+}>1Li8nZn{6zu*p8!6eVF4Ck@@wtl4PB4%x|(R#%`t zqRo8HsKegm09};OzHh-}s$RUU<*Z4#;yU|{or}R3)aBM8m(@h{3Va)k=69brDv&C%# z4a=o|wa8kaI^DZsIyE_~oG4e(9)>dqxfb@-V6NO+N5ejJUA}bCe<9IuLB>CyIe~4cx3B1*tR*JHwpQGJluXCtfpKsAioHuBMMX- zEr~M`OCaI71x7Rp`3hOVK#W7Z%HbI#8NyjhDUV@hkRTH5;7E%mYADscu<hexa> z8mgI47+T20Tfv!k(cq7AugcINDoUgZmKu=Q01Vjc8@DGp6li}(|eX< zyXHW=NQccjyH%uPa|?VOdHjP+O9hUd7zw#vm@*gqiGlaD zRr}YK_4T!T_3|Len8lwkoAHhXz!99#k$MX{;I~q=Z7}5l;*n7yB5ZD;#BZMfu#{eV znNOMs!147xcMSV69?wD_mA`PdH^t7Kt`EibgD99-_SKB%umwo@)HB6Wh8>PdCL)u0 ziQ}2?^FJe~@6%?8y>9L4Tgf!_Tj}PTclYmgum8ho^B=e=Gx^e6!31O2+d2J#I5M!?(6q6{8}brXUDagS;toV*a3k=YqMEj4UFT@tD<-cWRRC#`Wwhg`D1s zi&K|Z`nc$RA1?>*co?l~AzERZz54v%z?Yc^renl2+ade>RcrgL4ex&Ki&pDr4RCk7 z9htQFb4~=@Za<^Bt@sepb4Y~ftsE_G{7nm(%*f46vgj=XhV#xoBd;%6>oYN0_MQBC zG0C^EjeW*m^0fUe2ZYQhc+LAUkBhnplEkkYXf&Ojy>LyB&~Q43TNH?5qX64Ee2TMCnF)dG5=#8cB)+v2tN25 z=aPJJWws}((t;{Xpe|L)LQHo@l6W~LpsK8Ii@u&U7eXEcC8RdiKa-~wv9kHYjHikX z>0v*Gr^~Di-Ak@*i+$S5dA4L6H)&}KQ`L$|1A;T_v)C%?MM8t>joF(hnay3jw1B7v!rJ zski2-iV@J0l4ji9Yit}ZmEBG@ru9W;q_M0ENOCkdmkNo*jmm6NFykr3r`$h(w%!W~ zWHL7bD2aB18$^lgjIU2ldK;1$gB6J;L#q>pT%~}rw0^~{I~{mI6-n$5o*1P~Uf|ah zh)$+}DQ@{O@?P}u05x+y5Hzd(d5(oUw)4fI6?ci%@uJ=(K}ZG#(UCo(oc6w1(}i_ zJIH(DlDKqvM1$yc*>7``2G>1!&fDP&#asjXYKJKcZ$P%XfyjUSM49tK3o@#-`{PdY~}E6EiSW8s`yUg7cwpTN5V6dy{I;zkE$ zzTUIiRz`Ii%CE51E&}M*l$^~qpJ?!}R}h`*#;&)y3$hp%8%$;ii#@!~VHMZz!KyGS z-hbVflo}p|7)R037n7SyqMy05A?O|u&w?&oqK6z9M9avFw%grd#7xv%$zOdsPRpN7yEdO3 z3(!^Sq|8m9E9kB$Tj8p#fg}#9 zykh>#vdGgU=b?zRA`dyssEM*f*YUP9bDq(a>t-^*UuE+Z>+FGT;Vq?_ccpdjPl;k% z$?+G%1R9KnMxZwn1oZ6w_~D_5wM;H?6>#fI$Ke`*!sdm&qsQuD`swUSrD}O#QE91CskQ8mbxLd?J!rcCtmit>2a_9QX4i%w;Ut*v7 zgMi26kwB;kp>99*vw=2OzGWZ8#Znq?RGQ>S(t`6yg%Gk`e|9Noc%ysk3HJz~cHjJ_7xYpGY zset#gz)3aID^|d#d!K7O{TKg<4dN@__>2L_L%#G0oazZ&LSFY5XnmJsal0c(ZnZY} zhfKhyiNF`sZijG+H_1aY_=kChfcsf ztKMh&%r@!6S5ofx?}(Q^DGRJh%8TB@f4y{W*HA%xrGd(ULeuPn>5hR%#uW-c(JobrL$QxRi&;bBeRr%*5&Ym8y zlm3-VEAXiz66ef)gVrDziWT|RmBrRpIo6H3mEani5J$w9lk6dfDg0wszb?f`2Z0QghbOh-`;S@>fD-1;O1yz2$wi}w{PxBt66T%={%$qHU znp50ZT^%s9W=AJvTI3;V&j$Le=-6vBCu09@%&>xsLbE2wT(Sdao+jX2sWAf8&>3Jn ze{ni*opswX=Gg}1(%ZHw0N{jAa(bg?*9CX5`XRV2oegj*fx0Gd=5bbFr@wywD;P3c z=`=9>9vC_L#wq_p-thmBHT<@>*K;NQ$GAwKf|d-@Z)BeNYO7=#3o{l-1d%& z`dP7~21_|+Us{6h$NLMW-ab{~MzyyC5~NLhImizLBpfmcy@9q_LK&YMw*^6TmE4}s!M38i)`F#$kUvUz!9z<_dz7Mqx!=r#sv+Wo`qrSuw?HzNXG+yh+5_Ejn zdozxxd z39JA(5MkUZe8KoO2MY9ZJ(;CDb8vJ;z;JYBUEBY{J^E7XCq7sfsP`Aj#W(sf5=Z(V zS9r=7#?aO&(oTse7Kbxy0@wS{DoFf*8<#zr$RE1|{j=AtMf%O|4k6(}3V-d7xCq}I z8>wd0luw!W?>#JeXuP+UC_>uHUnmX?6h;#@h)f4E=yT9~u`dgv_8w8h-s1LfNDQNh zxrbVRxe}at480!)zc|sdc|z$b#vwxYBU?fmK2cgf4>}!sPuX45gpy0ZQo=3-6Gn>Y zBSlj}x#wFD93}5@N`t%qb*BO&1=d}Db9V~A#Xm{^`~3Fbcj|v6x!Lzom^Y%qbUJdhb zxCTWH#I&ZJdI8UhLW@7OK4*6lP;)p}OD-j34idK9T2j5ga6j4$<2&2Is5#{_dP51|=#oInI z!{fzoAbgz=@JEO@zERoo&W{xA`3I-XsvNUG`A4UZ+dhHW^iGeYu==NG#=k-TMwov@ z?m_y7KI3VH;N+biQIvB}BI}(VS<`;JQ1%8mZ+w-9+d-cCTsCKHWHC2tGEpmd3`@v5 zmDl*qau~SCoz<$E_ohy}K&!xO7g`dtXEK0vNtd$!CBJx-XUb?IhZxJ7C7GRRtjf9H z6q!XZcDEyloS0GDp0q)P99f5h5NTf{0##qPFP;t@zacU^4{#(EC5HKNTb6{y#Ejlr zF(h%DC7My67GF-9#3YNj`1%-9t`-dK*9}|(JPh{;V&>5GC z15;(C4%M9F00er~w|e0yzk)f+B3w2wG7aV3K$GYa5@++Qj$6BdY7x6N+SoH}=%wwT z$+%%p!+|H|?&OE)#?jpPjP9&!5OmxlK_RD!vK{1>(MK3VYk^?DYD| z84SSenwrYQBsN#Rw4@q3S3V+HI_KY3$!U?7J4Sw;<$C~J**LBi9vDS+H@9GiCVdU2 zNl9EOP@*fSt%qq481}s2N?m0k-qS{fM}bxykGWzj2T;ozCyzxrIUC(&>3N;V$eeL? z7E#%3($6tn;kjP=gKJzHj?NZs-pNAtPF}!R9PCuJW)wfR9lJdc02B>2V`CRTNy=0G zi`>MQBB=DIoRkxW<%K|3nnpzfO~K5-NfoPn+fqsL_BKV+)RoTJskTzfJayjUgDtMU zVDtAAPF(vzP+W2c_SZ7dO|+)&Fic!;hN^?2xE+pB`Z;Ij=~?LQo(WjPm5Crlg8tuH z2?htraYPc=n1N+Sl=M^b)R!g3ux<)K`jYJ`Y)|!cRv-28R{{Dx^Emwda4s?jo$+{& zD^t6&gylP9Ty+Q4amk#bfsDWFLD1(n^X+TKYhj(@RU|JD7m0AANcH&bo0TY_xz5=Y zk8192bk~e}SW$V=(BQL>!lSmfhA!4qf0WkOQtL`hq)Ao%juE5~J8-VXoIV_^0tJG;u{lH+ z9>G4QpbL>}m&;?su4P%AsE3w;FOilIA~i$cWQjjJ|qvXS=Y=EdwtXQdjgy&3H3hx7*Lfa;I% zT`8?zC-od>YL38>PS~K9X2g3j6fY88UG1E!LvTxSkpzd&?D7O}Mpr-|7!(B@d3?cu zE+FI8uXVcB6(6z?xVK?@>n=Aug^Aea3i@I$mqR}LXfFFgJ=^+q)#V5ZV=kjZJdZY2 z{6oDg$gi_DbCAVcrVjCHrMUzQ_0q=dW=j+NLM`mmLTlA7eEBGBn=^34T;4;vyqzk# zQK=AyauvaSGkf)6yMIr?!2>#@U{ja?^e=dc7kMD38O`SvnWa-?M#Lovnsq9TP<(ac zYK1#0X!7iBk&A}uCOzoHMl@WGia7IF>wbH7`2;u7Sepibkqm0@20^SW7oI00o=-Pm zL}URaSTBdTx!W0}!i?zyv5p|X3oz&>>R56Icf?HZ1Hq0oPzDGBj@ozN#Ait(T$cs; z0)*&79pv_b!w>OjkY2sw#ABzGiZwv?c6MxTmcuE8^+uEe zohhbH4-1QI^5}P5?q9__?C6Gw`yj*_FZIZBY)6;dvV=Qg(vqr(@LsPdPj7yImB8Z` zbseXip?xS9I*PN-2|3nrqQ+0DMGkPuuNk!q8ynalALfl$3PrwHwV?RiYW)Ef87~&= z6%NHu++ipOany3=B-eViHdYtIVvc%c`z(9;m8BtIreo1*zRDkBrXE6Z*x?9-?=Mel8+s z@YZ>HCkUpg)Rr;**@EcYau8djQmID#K-XeD*5YAD7GzKNNpYdb4P2 zw{CMWEn1H6f6?VsrE6Q8iJjSd6C?ALq6!I5WnU%T%oh?p#zC!)y5n?`&XK|KPtxC{ zCvFRexTZ$VnI+>E~6`KhyHX-3@h5 zhN?x`y)9%MA47Esu9=@~liTh=zfGR=cBpT9V``c9b&&u5{D13+zl7i@p5rpcua0Q= zD?j`XPy7EOJJhCV|36Rr@wq2CN(E|y-A+nvktp?)G^;=l>EA?inLA60>?V^9(r#^} zye}|60R8~^EDTAXyN$QYZu|lI{p|az85>HMX&OmQ(1*{Ywql-*0FY%8IviqR4Z$hrJc@+F&tZ2vId_lrRdA+ zianzV zr5bL7EUu|URFR=$Bt*)|qxu zug^Y0=HtHMJC7JZhv~HWi+4%NYTVjRM2ZwDWLc}$yd6jRnWyWRs^4aw>Rq@jt>n68 zD<=fhp^OmVg^!}-1j7U>zPE}mN>Tz5FQRiZ1?`1W_>n_=D;9U91)* zhYRo-BZS$lO0AERh8jn)3&1}eHs5NH#m+@^Lk4Oib&MRNL->Z?l_QTRAu}!r$v_YV zKEeh+4*5iPrpr<+1`)xk^y9Q5A+QpN_d-Tsg+K#6Y-4uV+BQXdV{hXe$xMOL!8@d+}!SDe#H(@xOLALb&L}_J%IJwGhtXUVj$Hp zqQx8EfNi79tX;?WSs1$jp%^|@q}eSuaX4j4#@J1o^0^6^Nzpm417>aken;S&zY&)) zrYCFvtc-okP_CNq%ME|%#@tMr`ne07^6?-r*<;a_)S{@=WpEF4K#_u`4diP<0RftXEpugbY{WgE+eh6kr1u4Yj2Zzx zgpI@x&Cu1h#3G6!@-}ln`)78V?dtdS{en9HQN`uuASKK$SItp;MDyo^=2}T_?=Pb<*=>y-!)c!TfN(nqCFNNzbMI;2+FY zp~g%YkIH=!Br^t7uoj>6^3M z`MqmbW-NMd#DPOAT2I4H)-A2L9SX}(mNmVo;7(qV`bzZ9{Cy?IyQ>7>u)(|j{i~+} zMbspuzy!k`J^+}nPw6S$xSm2h%C>>R5y3@Fp$6V1NqX10NVMd*lBb1Ik0i%z^lxy= zEthLpUFLcvZ~qZZIj!}dG0i`|8w9#r%Q<=aPS%d0$R|Jt_IPSua$X?!M7MJJh`6#I zIsNUT%||#U2H<0`Pe$Aqy5$E{84L!7>jHS7e85?afkdw-<~}oEQWO*&miuUKSR6ru zz+`b$87vH;TQFbR@zI61_=3)ps5GLj1TN|}^bO?Y*@w`mmR`NrLCiRtPBAcH7+%dW zyKV;-R?v1lr`(8;`s*y}jhce^zCyfDy{3``NwGaV=~C-PR?AgQjKgRG{b{W^N0dAn2{>8qOC9=+31)tbp{Y!3Q zIjbX%zO!8S>SOpN@QTYfY{)o%CD!Jbh0P${^IEXa*LDEdb(au<|67o7Va1D>`b0{Z zmHww_+9L;wLxOd)C0(*Q86^|lSBS#z;lDwY55g>>?H8hpzp5Dd|D7?AbG0@4PuV?G z#nv5J6r(rUqkrF~WjkHBseAD!%uk44 z6@5-{Xz^La9?v*_DIat9P7lU(_)ey$*)L7-IJ5Kh_g3Ez*a0x#Ipw}C?iH$IAaQV% zNXjGs2zbU(XUH^;`YqvzSm&f8%rj2CVc^$}ipzd{Xp9>T^UeT;W1no;)JfZilt$en zTU~18+~PfXpK}g1oOtQqZfzU3-SZPVt6;~K*Sqc8VF+GrG~7y>yN76}4HBnAKB&`j z5&~16h5J)z>aJr>-Xh$O?P6oi{lxp1tk(!_O4mxX=Qf@xL-eyWiS9<(Z;2MB~7Ar%1Q?Rgy6o7~BVe)%4f(rHM8LAXszn;eix=ZUB_ zX$RGCDc#9Z^1~I8O-FxZ3sxxFVeqzURly(-NSkOoN;|6^-!&8)uGP=fc!bk`(5cak5HI!{GuT zWHu8+pfFb&42`kWcvPTvN9|EuAex%%HtYOYR-8B3jq%O^=FGW=!M?K3n8QQptGxjl zn(#?Lu zpha~xAJ^fQMoK&XF7!AZ1(gC1ek@UPiub_?jm}`w=mdQu<9xWUd@SYmw-t$lAwWkG zM^%HR_+uT!q^~mYUMAF^LLvVwrmv6*??q6Sqo)K)3a1RS_=Hk?B!`-Bn3+%HQvJkE z{!HJn?OWGJa|?M3`e@=OKB(AT)ME!EP#NTLY!66#C7l~eI4ykOWtmeWkIYlk2LE#h zF>%Rq|ICyJDn02%Z5Af1)(>S1{sod^rxVqNvX0m{fvGR9xFt%+KB?jvZ5C25_;+$j zKy~b9lI2Te4H?NO4#CodVT-(C$E-YM6@{8hmm;dihDvmEEGdVfA2Aco*l3Zo2^Y1>8_%JU%?@WT$`G)zo))9qwOeL<9F zrc)Fb11-X1V9ZA*ys6*7?cQokO66)N^U;&GQ!O^(CWQsJR-c`f*iS{5G(y4xmlb*A z;hVUdk}=FMDAVe!GgIMu&h5rax6Cu@IMdVog{C&m1JiVlA?L2j?njtW7wk7PuB=fe z(y;xa)=|tZsIJNA=S#A7eT!@`Q6$jn8cfpJ)zDk;V4>fXJEN>^Jrb1HzlSOGHl4Fo3_b^3&KiVogU9$t`=76(UJnFuzPALPMZUpl#iwR`&Ioh7O&L^A9xKrT$4^pFP5!Yr`_IHwPaaD+hiv2Fe?{^y;vBD5+TOK`TK7?TK#w7@~uBY~$rNp?;b zHbyVi2q^O3ZE-sUP4&#bx8>^Z4iww}FUUw3I$KEEnV5R0{GZJ9ROKyc6h(}mT+XAL zt{X4eYFFl+mep3Br5W%gy09+8mxfbm!MN_=xa&U?GZc`9E`*T~O+f@+2#{Wp1m|KQ zy|3hVGTi6Y=|U>7elDqKGjpNgXk zebk)I$XhOQ{uJnNj_-4uW`uE13>;l2!(1k$mKIkr4lj?RKP+`!>(=4^R{z*3HN!T( zMpbcJbHJn)gJdx^f56t`NoAJV!Jn{0g=JF|yL zIP{Ik(g>r?2CP4C>9I?aV6dfy#|EOVD(OrvP>^lhbsV=9XD$AS5JVAC2;jueC44>@ znGi=v8lsnDa{jrWkxAvJGP&?1pMv{$A33i2%yO4yYc-8&^%F_hC|yITJH;dm5K-C? z!;(qaqD=8+DM2}Eh@#f#iFi*1a^aE%MGNp?guFq-^>J+goZ_~kfIwzW${~PW_=Fwt zu-yXQDjBwdNJ6543;qggssf&)1Gnag7bWlQYyAyIFQ`6L>aLyljoaeTom5m9uuQ@c z!P|n=;_pR`K$}qSa;!$t5%Kb%1#H`@A}t4;$V%l(&Qd(@D3 zV39ZBmOJqzW<>#Nr?Cd~eN7Rqw6$jN9Ch`kn z`91WxHG2Gd35tSFgQ6s;J6o))gfDuoe$DB}-nR3wIlVN99uS-W+BUL!l+ zH`@>?WHm8rkur*9cll$8A8^HEQ%EU}D#Z5x8*5`_zsofEdvodj!tg)W5dS{}+5dfW z$(sJ3w`;75uKcpVuPkeMakFTe2rnvt=CHDJGezZB5abgw5&#%8SaTR$SOcp~L2J|f ziS8HhArwOv6bV1Zj_jYzxSOd4LNX+5ezU#nJlFXu_wQ&ey&gd9jvy3ehQtMBR7vW9 zD@=(Znlu!f%MNO;;ST0+$7q4qYS`>NTf3R9w&~h~+H|zx&b^vAW{d5#?fmp$XH~yq zTXkJC=6c{>h5Ge_*1q@2c#Db%3@CdnXC87KbIkG2tgBa$P-u(Hzxqfz<};5MA!Fmw zI{s!goytG;T6UvV+=n>aD-EY0Bi#1U5@5!wk5?Zp)}SMU2H)|IlT%r`u+E4nBY&&i zItZ{A66tf6qd-7aitLUl4q?6|mTL;oP)8m^HIcO1gTt_y7#thgvC^cOxZ&NYlUTJp zBmw(c;^oNv>N$l>v1Z zuJF#094$487TW$E5I`d&WrhG~y@>vX3?~#c7Ahc;PXYudXEHDg z&TCYwR<~xamR8huD?&#_NhVaeEU9%N$$ZRa;UYv1{f%icdX!kp>Bh8=#7!|avk z?Y~d!e|##>^BdgpJ=5Fo@JK}8lM*X^$HeZxa@S6ya)4_0{RiY{{!YH^9X=c6Cp5Y>UyQk!U7XI|m7JhfI8*BII_TRS8KnT9mEwSDA@bb^|zOm0xZ!yhU zIUdb`BA#E_L59E$mA{R(ZwGI~BaFW_1wp}D_;BF)Ljpe<^au#kDhQVrup*%Q`raUN zF?QR#`QT_*{W?|+uL#=7Sp5X zpaVmnh(K+P6`})ed<*h&MVJA{{QBr-R@sDgM9aG{?YBk3_-P4sAFG6uJZ2`NV^xJr zaE$3h#6;h~lZ%_pKCPE}2k|1_HV(@%5;lla*3oyH^XeP7tR{0Ypue{+%OW8|dlTU* zS|pg;Dj0EV`H~AkR|6F-E>lrb)+{50;6SsJxpo0FUQCEF79`+Ylz=(Q{AoP+CTNu0 zE!220ZeW@LjRX)abU3kNe+eo@3#XXVoDk&&LAs>!Vn&IXBsk%G$&Q|ES*LobtAM4W z`qy>I0}uGc-z8v&dsyPNH1%K`&D)qZE?$<#O;2y#tgXK}?e!AQ|DevUu@|@WZX2F| zo}-@SG>E}6pBkpc!HC8qKqr>A1>poAxLift?oMo?Lyo=)_Cg!w=;U8Fb`T@%2p41E zm?6BEAl$_U^eP|)YuXw9a*lf!BPE&7zkDzdqHuY!a#rl(tzX?jjcUW>uUH5RhtwA= z#jU6wCufQ%p+~)i3)EHcKw?&Hz(C8v zU6^2o?;k{g&OuLv2ufKGu204Nd86Yb!}Cm44Nf*1Etn)!GBjhri}*N7q_8&JQ?~zu zEE^}&_l#y3$gEkHsG95&3e3D-_eTV++64eZsLwO5#M1O48TT2}?NNX{t@3-DLeru| zrzYHV-cP!zFBoBKmuW9y+KIjqaICyu3KbmPW~=s}9uzh?KY! zdeN|H7X``12nVAcx~NeQ9a)r-u8h%lvS?)7Uk6^@_QcSP(KfmjkxaU&4O+2suQs|e z2vKz9cN)8K+^!5UUd6#-Z^v4)vcE-2Di`a+VjU_Tt_R3^T~fiiTo=wNb*t z_OOAuk96{;0g^##04Us}&Wff49PvSL2VQ9&u zQUi5rm`WIP&!UuV_gTiR;L-P2Gc8?GX3D`ll+6ipG8l=ZihWv8*3GhjbH7D$jkc_^ z@ocm8@S;Y5fQbTAV=G;f`-LHn;TghnbT~x3N@p@;|K58M`xn8yR}_X@;;I}w_7(a8 z1AtmvY+GQn9~j9|F4q@vN@*|W2^Ke7mKWHEw!;s3BTRkpRlpCYUUgMw3+i4Qn(z@c z^2ys0ZZGG7p&P~$wLpfj#j0spsIen7!s!>#J8RoJX-jRRd|2t_Z-&>9#G-#8WG|#do+#ASwx<_sjHp6!1Z%2%MqW}gDT=+qCSZJrX)8bzq#0yu@`@O_ z8pwo@W|e{kq-ABxvU0eU`B0WHMM(0B!G?W*idTy!Cya)1WV<&KH5Z=X&D`~ixf#vy zP1|5P{w!syHctwveX=d)N1ts;PWjw3OZI~H#q_3@OpD4r3-H|mxFWcK5Fc@ta6ZzI zOYymofG6_rO^?Y*joL6Cev*i8NOwt?g$WT$ioGuL_8tAAI3Hbi-6aV-po(97Wz3Fs zogQm~N?89*Y$mrFi_==C`_MN^e<_|v{HOVWCkM=JW;6~y&D)B9gwv>Bew)bB&@FR? z8+=lCHSR%fQ#e4p%+fH&+UU-;**$^S9nnBu64<*ivdfCm-Gz^g(`b(LQp3{Fp1FRO zx&E55PF*|ApGfcTYNRqleCucOQQ?R?KoY1YbJ}+cAcay>T-UvMb<<4e#mUJvLg^5x zI)Pf9NG>PZs1b~{5aC$_IX$YC-9SxisIE0scZ{{%vrR|Q$;qNe09)le_D)!QBJW)FUaH`K@dpNA-OB3yQ>o=Z`Dc2(v_k+dx{rC7y zeBypjq|*a>X>==tcz2ZYkk{*^CqDL2xH4%CVL{0NRcIIONc!!3tjLA`S4&}gwPW`*)*6lJyO4WKMbi=>NkO`ULwlJ1xalR|+7 zg));uxk;hcgF$`4Hk@%U$)}If6L5tQeIk1F!OF!qz9=dAIP|Sab&P^3!#tZTw`@M! zRv=C}%EnZtZIpQHn9w0HmEN8y-g9>VDU79FL)e@}*MR*^Lo!Ub!s==D3jF7Nea$Pb z*JjBF=srwIFiW0%wpyXk!!hV^7^ie|u>*)x1=3ISl5Z}_I!`k_=Qk9WG*%aj?mfeX z@-5Ux$}7`TqOTB+a*rp`DpaKQf>2xvDt%mv>QS--lw_NTD{ZvR_)fFvt;QI`oIA{h zav8)iiR|xA{h^a`83ba(^Mhs-W-P1xfbvqb)}e0C_#y3W;bI7kY3;1#BW>P$+S2I} z)FgB8%*c&32krH*^>XBcgs-dqKq}cYg`yLNE@cM2BT7e}pnGB^I&-Ao#UAQM%|a?W z*1vGHfBsNk;*;~nN=1d)Up>hm@bPT%^6%SN!_*wnsq(F~;jZY^t%UG|S*y=FVZ;$n+t zlGBxcN*TALr>~`hK3fE*U86d~KtC01F>X(M2|&rfTUm~Pv@gkha;|PIU_p% zQntPr>MhoE%GBY6iF?KsO+2b@~8_7)2UAh7`LDJkl<#Y80`O8967@Bj%t#84)VdS22#WvS{QGRF@1U9Y}h|;g-!Q z`8jo!l%Y^cHV~sQ?-gXclZ{c^D`I(LGpD#SXnUedr@l5wdE&!Pfos(JM8r;spDXZ< zxt$7FuOQA=<1YSv{fed0B@YgnSNwb9h26H3#PBupuk%hyM$+D59_gtgJi)|)tT&lOYd z>p9>x`2}<>r<9FDn?x@U4(-gQ`|CIua3_-ywQ>59k|HXypZlfC+HxW+9gu){uzH5j7V)Cja@j^W{LhYD3 zROFK@e5d+YO-^zyU3|m;uR6RPFe<~{?;7v+uP69_5cw1got*zuzZ$-zKF3 z1Rb@io-3`tnXcaCv#ot;ZTqNl75@17!|Qwo2ZQ>ybDQIQ%enW!zvuMl`27~oJ1C;; zUR3Y0WNrJYD}47(39L6$7|)A3yso^R_le)`BQ{-ao?Fi=eHZyboBivLG+6J&Xv>f5 z(m%V80cpOE-th1JGI-u6ar)=>3?GtXV?uwV2Y;b&nqzt)KEwxgLVskne5iMsi67|q z?r^^J7ihvCgoo0E`Vb%5V{F1bD9)?G+Y;Wx(!ZGl2^+(h9>a8=$&@705^do-i(bF6 zX7^Jyev8aJIn=g!2|n=ucwEYTXc8O?pFX7R0}=v-qM#x@DxRW3QzlXjg``4ZUL7)9 z$RoLkdzNR2O*y89i+6ayBAhzYsXc1KznZ#~_~IV#JS^qWlt}BzCG3k5B!`Te(#!8C z?ed}kd&!P*J$Yp(Du3mPY;%vwSaUBAHA2QY$4AR1uex-$2Ojo0b1Dt4+nMKQR#djqcago-UPSwN*8axPb^>86wvgnC_iOW7qTc7`))oXP$n2mmfZL+d@$m*4S zLtCN!(N=ALsF2SbIlh4i(H1sKu~gBOE@_^!fduU~GNW0LbtC&XVzW zl9$M^Ofb&3PG2G6n=l(+h7vr%pj%hBe#8zs(+rBcM?*YreFq#UVoA1Ip@~+NX`Dg? zS6LW2u2R^X%Jy8aFrcP^*04Qj+=b?2TEH?~8w!+bn20-X6z5y5b_b>!D{G#}TA=N# z?xHT^>52T3T`uCLDNUDfsfjwmMscIvpxd&gZ0&9Caq3VGbBZs zw`>!;s_#4zZ42eb>IQOTCahi{s-w*pBq>8wy&1&>(+#x4xP;d=!*J>$c&(0yo9K~` z+FaD6-;IgB*Pen684-Wf5Gi?Rh?tAsq)k+KBUkg7q21M>JLF-;b;gUQjOs6UHp^7J z0HNUEp4F&Ppj!hqmQ&Up%orQRj-hR0w-D?%s3F_os<|cQ9PMMJz=Q@y8uXYP=+|Un zHjmnpT**>d$}#sKq0rVvhH3cD)tL@zY-%`@;L6Wv!JKP-2h^q2CaRhK_Qz%M)eI}x z+M_UAp4|g+4Xa1PN>P!ii>9LngZW&n3zjg8Z6-5}Y(;+oHx8UTnL$WV59qljDM7_v z#7WYY!lVsc=&|T}C)Ys$d~eZ2VS4Iu#-fAG6Q<(%guP>{dG7A#jDF_;d) zsW2frM2F@Wi7*|KQ-mAVOK1X)kbbEc;z;!%q&=l|-~Agfr%?e9543_{nY~7hD7(KcZ7=5sL zN<1~X_tYE}y9cP6bFhy#q!6!5`d~GN<)A7ba6YzY>!A76x?XGTc7a~zD#^#T_$zh~ z7_T0+32r_p@2NPEBZpXlbtUF)M9bJi^ScdvJ$pwcFqnNpB<-QNJXCl-wC8WDb&%%Z zD$}(RoK9XCM_0=C?7mvq20dg5s08o&R+@o1fy%0tXu$1x1v0yZvvc<#Zc-hX7LZKp z;FQrsm|4dti$`(AU5CT0QVz_fd_2|@282D5s6XxSPnsch`1W?Bt|_I!IOQjpI7k5< zpE!yD1^iE52+@*)85rj_5N9>bq8b{EyX!bF4*FGBrdYlL65~0hmzsy2+#rdfzL<|c zub7^4s0J4y^ETeCf+luhR{C)}OM#v{7@(+{sBNu}n=6<@9M+Xg05x|}qVoxd!HR0C zi>s^*t+^ZP(|`vr@d-`=IYjm+3AV1IGjjA(M}Agf11GpX@|VvzdUeg|rhcuXCsyUf z95Ej_JuSzaS(*NE1*e*)+fngKGZnfJsR`JST4ED;CaU#V-OEE~k0?;$^Z{0Gpe&i( z)m{3SK@YK`TRf!Disc+g+E=6(-3$50MqnMCDu(nTtt_5iGu3JpvQQwgWsyKjw7N%% z_p;Ohos{x*3jNcPn>Kh5j%nu#KHQ(XbbrDv_a{&2dClm7b>#SUw?c?DOYqqm1#>1| z_+A?h(^|fniw2`IM$2kvERgcD%(q_g;Ku5m9@QdL@FK;@-{q~-2{L8p#urDzCT)_g zm05Iwr7j5*Wq0(RA~qbh;*~-Hn9oc*r>X)^4apU#<@H~#3G0?;SBP`HJhP8YHV1dQ zhzkLVb)ST3X%?LbJ2%0O@+`*X@tkD)gxhgxro0fP48kr|7sGU(6GI&L2xH7~ydxXx zgeK@7jdeE)yjAmAF;6ubs&*6F#k9*g1M?!CZ1m17SlvWkbme+DyA(N znzzXC+jk^&PU!}4%7V(}x_CzTd#X1@^(Jah@v+FOp!Kq z-l&0yswrdP*X2aC(j3zT<_lc=e5&LZ9QcxLciEDxOY@<& zOgq3TjOm^tXFmNx6|Bg-!5x70bjs(0#SQL4Icgiw11@HCFL zS)3C@*$=_rvnZd@H@0ZTq(JG5j)kyF1p}&1S+TEdDDbP|Kr89!Pg3yamqmhpYkF8T zCXopR|5H7xG`+|K!|#}0mCM`W1COb@oRTfX_JlQkj;44qT%=iA9`$*E`RT$H)PYAS zn+w&u2z+9Ux-zJ%FORD?5&{<3Y#!(>Zg?;H5iokdrs)7%;CUO6JnO&{FagvM)veTO zs%RS!HY<>lS7vNic7?gGuuGf)lLtmP=q zCKN>8N_F3Mu;kQR%`eJTE)4$rG~!!Lm=x|jB8QR#=agW+;CU}Juy6FFd1sa=y#VLF zh~971*^$T&Eb$}ICn%)N>Xsb6;?yUu#X)QdQ2QamJt2d>*qTpllQs8&M_usp?sr36jDGkSetXNYfz$ThCK2*dJA9`1cw3(~3f= zMWI!DJ2A9U1fmV+i%_&+!qH4wlH`k|@DAopbg*O{me#UZ3Q@-~_vzK*^3Le}U@lUW z9;;jTiYJGSEBMtpg!}_^v%v`3`6_VXxcB%)_wlx#ux!2jr=ONe5zj7*MJ1tWJyRPT za8MsS!dbtTG?uKpZvky*k#sw(k?nXSU01J5gnD#i#Lbppa6I*U>9jw!Jx%eP8Hc~Dqr{!y@;Ws!R5OyWwcxq&%)b8RX;Y8Fx^&`ur+W)$A1Iky| z^_-ngdG|T-Dy>R@_Cdv`z!iBDsBpJQSE<5}G|Vr8fiY{&Ab6%5BZ)(UR5 zN-&1K+yQUC)M=L9?zSk|jXI%<%p=55PovPRrkmZzOJS_x7N9;p-`sz^E>G2hoY6~N zPb?v~8-dK}z{+k2SiL8La-t3OfV4g3+KejxL)sHVcf@?Ir6ZGRcK4MS|P+Ur> zSm;V-uwb3t5d37SJDalmY(o8a5v-*l2FivC}c zeNhDkl1Qxl&Ma&2Y|*kO6zy@9MUM-jyw~?K%q_QyqT;lelbU?A;A<*@I@O<)sq5Ax zRkBIvwG=B+h5wOHTh%rH5WgtNCb$Y+UFg+4g`#Qzpzk?(Af*?MLBM*4l<8TW&ei_(Lh}=o<%FKTgCLuVt<#c=jK5hu_ zSB}R`!Y$ePE&;CQRy;B}%simA)xI8OXHWi`65)5qD-7qt)bK^%9sPBR^_-?e9}(9JJ{ z-aNc--NQYhkgJn>GIv8bv(AL5#l-jU&f8x~%RSa<7S*!9t(10U5sW$w*{;2*%l-p* z{NO7y_;o);;tz#Vjee8nIO|_c$knvXC3oe{OAsXcO*iYMQ_>N7p1e1DoI`WY5pRm> zhJpd68&mCIt6IUlxW7+4{jPU2(yWsi)crHPMK2GkDqin~0q;C~`ThY?{1UVi13QtP z5k<{EkpGo5%NCW{h5VX~{s+=b*~Q7y&ip@o6`{)iVUE3NtJA&!031}up+9UR zQdJNPrx0Ys(33F}d(y6irA|ZJlzYeghWu)Q&!Qm7s@RkHRJ`nTZ;i1mko3OgJ>xm! zJmYNV_xJsVGQfI8`E^tYPaEh60;xAo7zqW&Swnp|>JE~WnQZTeXEWI`mITkY@5qMb zozNbo7IKGmSE`59%Is=xwGMNJErt5;j8X|(4SE|gy8PCGv}*0`Hhh+kg&E(wUD5xWgQrU5nH0X|z=+wLQ=|NpYm}LR zw3bnTXci&W>~tM~*do>0+Gv_-oN_MZt>fnk9G9o{HjH5_P!*kvX8&DxrC0_TuQ(sE z4I32xwAyjZ^JtUy9pzoM0FQb#^-XBqY`77 zO5i7Ju;Os7>g?8~Q6gdB-P>HUmDks@rc4g0#*^>Ei)|I2dA0Amar?5s$yV#w#{j(8 z^ENRU(h$r0j)(hjmGG?tzFvGvqA|HB+o4N(!Ui;#0yo%%Kkg&AuOasgSZ+^xfm{TC zAa#uD`${;^7LOvCG01p`H3CStJmE_O?mY({iE~Z_Xdy4#LrFQM<4y%6FSak!jN6&(QwEwJdG9hx^oboMw^)_h z;+~)cn-!5_lk$?daPB(|zv*tG?(yL$Sjch+39BqMKbpn>j`?bN^T-kkiu4bVvQ>hY z59#ThOthv%Oc@6mtD-}wEhHm5q=e>P3c4u#@V^nt#aEj;XumlV+o=Cz&V-twjjQQ@ zKqFP%(gpiBXCjZ*dQ8a8Dv@`T!WwrglA=@+IUH@g4GVk2?ugWNiY;yYe&ivBiFs;l z5p+ro3KR)KS~@VTDTPf^duv2NSQ9FAu?ffTG1{5q^N1b1<8@XeX`ER7p0n?E*8A1Z z-S?HZ_hZkR9&kOLe>7o8n9&C*-{`@TEZ^`!lMJ5u9Vb~l!$)rr-Do}fe-ZXhVVZ5r zwrEz`wr$(C?X0wI+g7D*+qP}9(v`OJ=3E_O;RZh4cANJCm(^ ztqeWoCf@gi%#Aak>Xp-jXME?=dk_lgQ@Edo?y_gVBk`_2)WFSKvd*H+@$2ZG2Mv8Wv^I7O+hK|7ZEGIeSUlTTpLdF5ncC z>9uqZ{WnL~0yB-8Bg}*o@Up3_MM;ygER$TJBx8_#%Hx$xjtYBf3n>%TMnJ#KOOA}CyKc+Ef`g5?@0s23Gbdr~kID&5)i5aX zk~DKWMLkm~TNN{BMM3`idTCu1#{5|Kg{7O~w3ZIeZJUT(B5(b?-%AiUC5sr-yU!9l zf5riGL5A!&t+lwwS~?-)76|YO#d@A(@4vuij@B+Zn78g9Q}dC+NlrC6`u7{Q*ypzZV{)DkWeWdj>q zg$4>kGrylfWQQ1F%9oE42zgUoH9{n&AAZ%(pCnn&+a(lpw?+S~OG0%~RuZ%toUngK z?1}j8!wo-DWA7KuC!?m|=0K5?_kds9X4K$2kTmq0^_?^Z?l+PBCRnu1lnP>+K8t1y z7GF~tyUj3H8R)lk%1~V_AK|%vCN3(oT=%yXIy3M@q-LnL!HQEmrsJ^t)w5O2{vf!O zh6ss9`ihlU>>kQ{vND{yjUrRx&oVq|NKQGX^+s8Frv^MGZA$wEdzJ-fBk$17ID!#J z9dx3l4@}*R;Vf0kJJnLcXHjz98ylRq{k2r=Cy!!n#aB--k2kKXNrcg2|&PWesVdU19F{UA2igsPS^nMm3&@!MOnOkZ;Wj*DmE!S5Y z=O|rsJ|ssO%b?vFnbepo9yz27k%DVes_h%Pncjt&$R0SEhLWw;G4>__ht3>6z(0Bl zrEg1y(bA+~<@3u=cm-aDms@EqD69!&?g$nYFx2^jJ&2ONm>XyoCAy32QG_=_kUqpi+L^)c@39%f zWfuEGQN+)EQJWS}_%Odo`kCjX@P__F%!~xX01L=9enen*9shbH`G;$PSbIGpZ8TS) zUB)p2L_bd_^d-0lRsRFZo`q4^S^BX8T2KeFpQo)ztMqKU^<5a~UN&U!gIW+4xMqtb zt|a`W1%OR0p|(2ZBL3z+V{3=1#LyN&St(rq2Z7$!oIJZf0rVTm=HvTuQgIKs1#tZh7^%Rj?G@;&xBfYWP2kaQ>puks0GDG( zmZ$VT4BqBfKtDBmhwGY2H~B(kfT}J$P3qiHwai-Mt4fnptpX)gxg*2eV56O0NC#Cm z$$#=kx*@PdYHU&-6*^aCH|IOQdHr!q9-*i&4~ES#yhsVx zC8W9OnFqMR9C~-YeWWu(w2d3_9Y(!b$xnfZc*n>jftZ)SXQSvc>Wn^k;izAE zaCqbks8Oj^>vIR0f`?3a7!>PK@Unz^ebQ@evWDdfh(5tHZi_{261h?E_-S|7Ub6}y ziMEUF0;>PnbQ>&;ke_2P0VzHdI3%VP>jb~r=BHyAo^dpL%k47ZUXj@{=H8Kc)ketF zdxlxGilE3M9**C8&iH>$GplGRX{jLp4BZ^v<7ZW)2o^L~v0?o+FKD|8 zpDP0;Aq7q%SQKgpnMcrmUGiF$l^97P zy*Orc(e(K9P0P~P^1|E4`|(xN}w8Gga7X4ft8axBX?dLqGBm) zs)Q*GkM-1_GV1~VOimO<+d)Fdd7g6lB?I}qvm3MR>g;UF(!RCMvn;5nzOhRe@qgrJ?G7<$QmGVGGvWdKST+W zHpem7CY#gf-?7%D*L_j);k6ReWEzS}j6ktodA4%q7c4(ZjY$_Q8G%-Kj^cnWwT2bQ zToH$plYqByH5E!l4UQ0pPV49C_;8x4IL$$%m3r{j80R55JlNxE*m0zd>%rI5Gs7{p z+RL;sn6A(?*60ycZFROI6O`v6oD{UFs%sH5osDJsfCh?y~4mBPo)-Xg@{mQ0i zjcx>SNH|q71S6BdIAyWKK{De)f@)HblH1IhYdIfhuEtolvNyHUVN)PildDa^s-yI; zlAIN?HtT^Z)vBggEUny9PC)P)+RxgRG;_+7wOo`L;r=yimISJfju}1Y7kX)ioXZlu zOi?xmEOWaK8rgyAte7FHLk-)&KBy3@dX65wzSa>qgn%mMokza1Cz!DdGXcIjdr0q!TlRPWO1MxFi$w`a zAF7hlA~^a^(DwJhMBNrH*ZEBtkITAY3J-3QAre!}T|foV zSEXl`7+1!locmxWz#L<8KQRk&)oD0v&x&{n%NQu9#Xgw*ScaijQ@6Wq%gTLYu|>pH zXfyLIFlqhoP4w7bVEPc&@?y#NYsM*TKBX0Xp@7S{Q3jwuwyfc6C51 z&`W;2g-rup0Y0~dokb-LTGD(!NVci68#kg1lnKr;wa>BOZHd6}`r3q+9CBD~$XAm; z+*-zWWdLo<0k=ngxB(eo3-)$s{;<6V=mayqHt|EN_H%s%=xmwT-2&LQ0_k-8>iA^H zohkTaQ}_x7I`j3>{h-5+`)Xr+p(E^941TBk4E3M^x^e;OtOLaBNsQb?AJFUbo?|#- z|83>c>?<UB|#aoJ#wJvvgRYaU7~y!v?(XC5xhZk%Uz^tw#9)qM`L=H>%7iXo{2DP zQKSktMb#9dv-dfM;u=<@zDdz+XrF=}HMB)tyS{qlF7>>P5i?Y=7I$XjKSIwU*zF%B z(|LtD?GAUxwR_E*Jq5OVV!fH}+PCJ({`IDJ2-Gf$x98#&h5HGt^GLz@n~DB|L;Wki zkPmmisWmEIqk^nTVs4nnDYz5&z4Iq`0|B#cOs#+ha6X^TkfGB^cV0W9CxnZ2cvc9F zq!p5jcer(*&FaX6d^Xy0`4D-g1tmvTa3X1t6Q)r~B1nnS`QT*4LS3s}BvTwN1K`-I z{oc?~t9&r529YX0OT1qtN=2M=zu$d07x?UGRn=&MQy`XL2BeouhaSxSof`z+<{$Mf z&_1}iO2};4?(CIM(0?*AQ?T&mkKc@p>G%Ecz3lS8sdr1;8tOZl+y18^X|(dclzKjk zJ1&;n@$u1;GVm=rKp=m{Ba*NprXzd%>E+7_VVv~WD|IL#eul?(meO&XApOH94B(*m>z@GIe>JXbFr3urVYJCZ^2}2qfTv`E#lW7F>PCzb-KBKN1&b zX&EmMT{)@;=0iTJmMq{+MQk_>=k1&lPLGFq>zvqs5vFlh>R$+}pCOL3YHC89%kpO7>GRpkn z+4@p9cSnD<43rX78F$C-?Z)>~TWzLRGlAtHibCyH56)<0p$%^el|qZoc6?=#YEe@} zbQy!mA$A8^Qu;Ca=h)v!6IUeZOtd9-Fe_t53sHHdk+u;5&=kjYHKj=Ug>I!M?^{ma z(9TMyRIrz*Kl7ugY&gx;PAG+Ai2j!8Aauh)iJ1e_!LhT_$a z5jr0K^H}UEcWmxtlp9VB2qBso@owbLyVCx=tV$+;uSdTzUJ3a%zWRMqu8<-T?U$N0 zG?4Fzei*Jo!ggG+%LhT+QZ*k?L%T_nd1Efhz33<;JX5yp6;SF*M{Md!58T9`jnI#f zcZSBf&1m*1!ys(3Wo%=)U24*Bq-)HV6MVR+BImTaMu$mt%?(0Zvi9_GCFHqM)hiq; z%w>O6ckj|P`ne3z0c-pW%zK`^lCgvWm682H_>DIj_g8U;clsCXX|}{2#PxjV>4|RP z&Fu*v(arU{ZKC+18$sLpoLy?OO9jl1la=5E^NW0;6`A5Ls1YBKjrDIEth0e5$jkU6 zYMl{p3n72aPrqNsc0caWh3AxA>hgS6IdLwE)( zq$miuPk_HPY+Zmrw9KU!z6C(9IG#4S@Opf5K7nh)4u7T(Cx#gk{s2mZklw4tEq;h& zjAM<{596BOA5W$oQ144PtgOZE*oV?p<&iRi^Ex$w(ie{*Xg2C-_UNmPqr|=@%64wm z8n>aGagl1Hx;eEDG5d)MBBa*mGUU zxAW5|T#|g29BSvd$nT2I9~y@w57HDxu5g}aF%y4scsrX8S%^64r=fT^B8r^6A2}nm zPigx&ZKU-^i^QGON)n}C!X=h7<}`z5@v;C;Y29&=5=~NhuvE~`Uz--%5ZDT{M z1otpt79i{R61gEd`JGUF3T;x8VTE_S*N~1#QqN1x-JIFPD;E7}AhQDq*4VGTYKHZO zQlv&M6Ob;}+EOmj`^4jeW=~=`k<0rN1cZ@a|oYCFsYWa@ua;~zaz}xKkKHO>OAqOo%4(dM6$W2i>rjE0dyA2k{cPI zzqnux@52U9CGsMR;LtTL?yvkLvMr4+@CEsD$(WctC3)ZZwM-tl2zN%;LS!+y0{s{O zqYJQ*PV$$`V1)nR;@5i2mFyXvGFuzziutAzOEr8hXLAS~{K2rNwwneHGNHjIE~E&>GS&d3FN19!Wusif^AYD zMT50eKPC*3A>*O-tA!=fTEhy>%%MyFROAqW3mil-(AZz2DbDX?uXy8O)2yerU(ojC z*&my(&F55kSCny;P5q~@BEHUJXi@Lx&y_^)6grr(-5?%i{lcad*Yj}+F1saO*x~|& z6zRJd5XK177?5hTrCH!g+?hmyHiOVSqw(pVBR$FqvO`r4SGus+8kjKNHNVJpKENh< zAGuM1nm^a-`5Sn7;DH~7eN{XFMFnK^aj{*ESRB0RCJn$w%1V-`d`71?&fuh+{T3kc>wMKw@B?VvgD`w3N1C+hyo z^sOh1w$>n|o=Ds0XtHKURPO87CLk4-QoURHQ^{r3;ZrHU=%1ky)e{Abv;dEilY@X=1m9ktONP&!km8dp+bk~tKCbNtPtZf10j%~sRO|qHa>y@$7_<;fenIy>Il?!tr zAbyYJG=0BH!W6{|aBvzSyK~mgD!bfXVWRF|TIeHe<7_Z8g^St4HA>Ems;Ggdkp@Yh z;RSGH%$5KQ`iI_&Ff{s|Po#CyLEv7s@MPqc>1y zuCbH1U5B|v14arqc`Yl1VG+4;7-k%@=+=D+&aKFImeLM7`rC%Xc&6J(F(;e$uMRp` zqrFzd9kXt?@TaCgnW;+5V25v;%s0C%LJDoh*jyvqw@9zEfZaBjcPl=B+gv96#2!Z%md zQ<7ss7c(a;A_tTSV*1cb$b+VAnYcz?)A9n7rehMk?u0UKuT{+ggP)UfF}cq09B*-3SW+%Kdg5rf)s7o8i)S4mzyj z>i-Ssa38Y5 z+(BZBz6`ZGB?&^i2FkW%dmct(^p|FriNoZrrJkNj`5ZW<+!D{$b7N&oyGr2r@2?H^l4b1ymuG)cD;n@=-SV#(ULEK$-%CZK876tYGoS5*I8sKQ;S$#e@2p45 z;Erv^6p&U4Bl<*POdx1OwG`UDz@T5k>1A3nRTk-;Wf{gLYug0|JGkhbhY;VrkwC0N z|C9#s%^+{eX@fnt+&;(=x=9UcCcEo9@rYE&jg$kB{7`eVNFqVy_yAks@-*}c&%VX< zgxhdzGmpN7@yHyUc_iURKXX~1lhubKmqQ=!7*aI%R;Ew8f^x|@?o@u*=;bql9t45M zkD}EdRLR{$_erV*o4K~>4*r09kxny`tr8V`0MP{LeK``UqF-Wm6%%PscYcEm{V>Y{ z2cvBG6o$-zOu#+SbF`a;t;AEYJ_2XxbE2%v0`E^J5{;_k2R^xS^S|1e^>a*8%K=bF z*Rba4kfsRB)I6|{?7>{kClfk6y9eHUSfvsl1C=T$ITGYVErezBqwPpy8feEe#lPmuro zx7~e?6>J#8Z?E&j?-cldG-m&C2?^QSn3$XXw+K`Ggls=Qa>&=7ssOS;-ygw1wAsO7 z6sSd*xzaK#X7rSzDEdMtX|2VPd6aNcUOzZv?kv_}w{Yos4j$9)yC=S^mZxJi0G3Ll zIAMtaFHi<*Gxf#V!MJs_m}@wU{UnP>g1I=H={TmKfs6rxjE)qOjbh2ZxMcGdX*FPX z4CiAUh1Y(*4Pon{i<3o@mdzV? z8N&i)prLRA&xwGj_2-Awc~o;)9>pb5c)uJ-$Yk&t7pnj9yBb=D_uX`%eJu7wa<*Oj z@#fVS?0|5h=V$o+JGJ60`tqkUg5Lx*mf_U2JZ_*N`RAjUrn*SLC8Iin$0+_NL)R%X z#?Zkd__+j52?{*&#OQ1`%nxY;NeF2oG!{Jk>VtW@FrBL?c;9!@+A?5Cf_sX%Vdz_@ zY<_{8hSUP|SE_Q!1YXE981yDyfPXg8t;5)~E#I-){*KlELoVy@vHH(ir6?n}!4L19 z$Zo&iN>Z3}ABYM_cn=?m6q+lEVnL!NizxuSugqZrg_XvlNr&=IJ?LMa^a}J^P(ID6 zFhqjLJ9!?p<9YW@LGI-A{ID{d5`vMU{pm)oUj~at$J5zw*`eujGd!dffJaGkZ-aT< zHVR?GhaL0*hoH|RS>M1s%ckm9T7Zci)Qoo*cJi(_BOYu>`CxxjCB!$B}X^D8~!|ivdS? z^-|b9!Q38W)QYvMg=1#R6qX4(uX(_)49B(yz&pWZdVh<@iR|VnbrwBr^FFvK_07#M z)C>5D-M@(j4;PbG)vGf9Vn8f#wi_&QwlOh~S(U6W4?Rg_AsHCFC_oOJkBlxuA|OC;uoQg$y&_=R8fJ}FWX&ZpInE)a+N~CIVyVVX`SZl z#?*W08GVwnT5|?wrGCDDMt|#@A~5*wB0aw$6y^WkMgA52?@SF}#HEFiaR1 z3ZWNH!LAjckE?aoWPldHF1EWopEez1RA1k6da?mqV^nc#^myT*q9H`DCa(RV@y3Ty z)>_j?#9B$`9=Lgj$w+xw>T>BHr4Gn`7RsLw+Mv6`Vfw5-3mhA{8un}?ZB2G12h2SL z@(VPz)tx-O8%gXvtVbRnEo*E*vhf5r;Pf1OclC7aiR^G-`IC7Iu0Skjjix-{n-g#N zRLWnp?%51D0{PNC?%VM>bPda5KQhubKIj6j{% zoA1{^rk<3jjxtALqo&r^Kvh9vqhYSgr@v!Fr9_r}9Z}wiv8X>864yYlT^wpsXUbJjlSYI197Adheo z6;YVsAo8(eeaRfK#J3e?(@5LnwpoD+9+3}iuODQnxpS;+vCmd0(+y?2Ce0=Kwky2o z2e3|L(I{)eBQi9NjcfWNMt^>rxQXB(bdKnNP1nbdg48OV>7H$S!i)9>Zl0sKUJ^t> zIZ97k(67Py7)IP_av^5*2;NpQd?b|m$S`bVyrchGZJ#4u?DO_1kEJwUjE-Fc|4jMY zGIei8kKBRPnm4kgwdT5+w=BX43|GZXtRWS*_Bo3h*p9Zon}hpqfGVjJ~BH43AR{X^Q3<BN(O4pUh2uMHG)UUOuIr;XRnl#g=oibm!3HOAE~9 z-Q)-JsQneCcTT)A%oq7#r+y57`4WEZ`G=G*kpGjZ(k8S2urB?Ed;pGywhqQ_|L`mQ z_ha9F>i>1j-1dK*mMg2oJMzR`ab z;oyXSP34VzwZQ#R1vPX;LP#Q@+zMF)L)6VBHkm6llH8v}JXBG`B;Qysx`6h<;_Kah z7DZ%v-kvdvI(9K;b{;0}I^J}=eEFDZyO`P0o%zAtXNbbFsBEO5Halvd6dd-ZVP%|0 z<(9ikAaqprn{$sguylzNT5*A^5d)HDq)9gxRA2ctp0> z(f{z}vFy_A6>EdL@dIc4I|P@q;?6E+?C?qaslqh?Y+NM7DVUN=+ok=}_rMZMl- z_5cM^V_-KM`96~X!@8zkk&IFh8=$70dEzg0Yw2sd@BX81k z(L!Yfs-jN>tMeM+(2edCJCE?A=Xd03MxT?<15t@r2nnV%Gi;Y94Ss%4x@D zIh*h)6!0FBk^Uxp%g8TyBK7bX|9g_NT>f#Xg?GqtV)<~{23>MWCliYC zxu>YYnxXj_gH!A=)@cdX%(Jf4xX~fR%?xqrJj761GNSvRBa+k&Ql9a;>uh0HlJgh` zcobPhK{1?53id#3N{d?R(PbGoMNkIqf072Hp%`e!N)ZD;LhCpK`)Wfr!qb9IrPDB& zs=f@1oi`<>oKk!WA)L9^b>)*V7NdoAEj(CXVW0AI7$tVXz}NpaA@|p7xmA7~67~H` za(++AVgKW`{EuPLzrUQ`D*y5@_F-Kkt_?~l^g|KEBDVmi$(^SJiHu8TMV8dEKq9=Bq{RA+1hlsgA8>zV$GCeRpmwq{k;v2!+ea_5ak%+fvYoM>1 zn~v=%Q!in4W!6MCI*RhB9(E@4N;Xp{4ryR6pj_rWVV6BF=dq$TTV3e zlzMKsXbcPmJ5(QNdKS2h)jX^+-X%-XV(Mb4)@j>U73oxnZ&Uc2>pV_wPUpA%L1Vl; zKdjW5p+#xabxo^sN$@3ZN**&InRmoWl7aDWg5F7D#Q?=AE4`^maXr_OEqlpxw~433 z42)BL6-d$~DRryWUfZH+%T7w!(%73P%`j=^pk4*pP|`4#I?7a{glaof9GcQ_Y^IN9 zfy73DD>xYlRk+V5iwJ_g+A{!_%Xh;w$M86D*~&Rrlqs+G-wiGV9GA+IQt-lG>IO{H zDQh9un$+@?La{Y>Y*wZ?nrI?K@WL5lQx7*lu|(vF+}Gk>pr4I9XJ1Y}oov-g3Q)Pn z1b2#vu`CXgm*iJM91)c4Hx1y5>j9>d-k^ z!o32NiF9gccDhRd$OybJ5IVasAO?;@_^xS8#_@O-5G1&(6`z$o8D z??>eq0Xi0ZEaNe(0FQ=n0Qpkn8~6#Pxr1MiXv-;jSGEg`B8z2O>j0b;rjWK6quTJk zj#t*D2~9zgzT&q-Q0N_pEokwk_X-Z`5BMJ9D?o0CUwVpCU3vCL*)u3P5Ys9%iNBw- z%Cck?J$NY(>Jl2r39R#hth0LbYooA9ea zxo#vR)AZT*@?zVsTL?}QlKaOuIrt2f`p35^yt0Zf6`5s{WKfC|U|TX_=o|;{Ou*{9 zor92sc;!%&d{V;z&tVDjF`F0$$n2fAKhia~NmKcp)Luy?OG>unU^a|~^?U3=-nqk? zf<+!R)vrx}FwXrJ#_f5cy)}6^#a@>UtE3`*e=fW!Qi!?{d+eg7l@9aJhc+~N$hXFK zp&>SpiqaCl_*jpB4j7+Tz0668d4L~w%s#^2Wi-8UOlh<>eMXY=K|bX8oh^0F41z?c zTfr}Q#1JG>SG*j7dO5OuHZJ~AnerCLiJfLp8~C;UGW0jp^H&w4QKV&v{jOqD5dZfo z_IGyNTUF=Vi5=ZXwq8F`Mo}CxFD|H<#)8*ODgO0GQ)5tbv7)?^z@P=&1gL5YR=QQ( z4V>Fm(cyID_BsZPQkpqk){R)%6-UPwH9V*Ebaw2Md-fB@6^H5b@lMZAz-Itw5DMz? z)+&6zA#hPUvEeOxUIlo;B)RS1QzeYa$mHq=fp47}s_uPoc`Uu?UB1IlP*Ea!m^~Tq6LcAk(khB-N@msW!Ze+RX^u+x}q6Eb5i7$v>@6R zmY2@*n=GJ?QmE6UVjb>j2`7c}o+xxSeHj0kjZ(!wkvZO1uRsuj6>AYDy?uy2fp5<& zW&~`*CGyzAAYQ)_ZV&-O-qpp)GEsjWPjO9Ei{(Q?tcBUT+OB;dciG3mDKr)z!$j7Y z?tCKJ;(svd?#hsD12#p>2yL z<_DUk&ZYG;?q!+{BqE}TMm?+!k80Z5Hr6a6S>1gZ+7QNXN92Qode(=oq?oRGbu*XB zspgR(AvU+W=%`QzugI&DI1QYIDE)+nDFfONG5HsIv9_lji;%qS{y$~PUz7{_7elIQ zUe&@ha$D~Z$B3D@^h;N;nYg@8Ucs<}9ZI$xAIjZ1=zICdi+2ees4fTGzX7}WC_L6r zAaBnU>14e*K^BY68~yMf{POmHsNcZ*KL7!L1>I*J0glRhh7j`GW(ARhA_ygmGJpj_ zWTI^<+o#y3>;vBO%)HFMh2ar4W@EGay-U`Xz`?tm1_tnoz)_*ahjB~)l6cMN)gVZ8 zDAmT;?(mBwb{ea@!3zd8ilUDnC`=Iw*26}p`TRlgA%zy-l#L@oU39{Awh-olsnAKn z%)YllyT@xxHut1?L@}Q>Ke0of;2j}M`WE&?biXBb4-a{vbFcEKRzH#?m1c!j*Oa|v z4;{uT?;&yqGK3lgKRKE(+IWz(P*)uW z+#Z%=#~TjLan7N}%>km+dd}Iif6GIRkgeR$AS~O#z7WeQS48!!P0YO>BsJk#qeHBX z7FGSBq9*C6gh%xet-%FVFU$Y_# z@Sn1-6OZ-cKiZVrwIle=llHR$2;z&0GjfTMB?;kLD>q!~T*h1~-eJE2;CM64WS|Ld z#s+tcq8z7fB-;wtm{ORScG#H6KJKoLIs8n?2jK-+At5+Go(zbuMrwn&SCZQv`TK-I z`aW>HTbx?!TG}+$IjH~CNI^@Rp3relC7UvLMa-FLA>s!Te9krTSQhA1Y0?UvsH7hiIj$O_uQg_?QoDE(OYX45W*KE_JWLfWFlc3M0V+9PxsjGB%uEWwaFEnu=Y@SrEy{5E{=HqtM< zN6?rjYV_EbWeYSqlweHQJBO>SA#@6x=G{}Kmo7O2+hr9MXS6Vl%6GekNP>*dobnMm zVOu=UjcT}d4Qi#4@mimN6uIO-Dk4$v_$BF|N-;<+kU1Q#l8z1&$)!N+x4+(cLO@Zk z5s-eXdl|GF59!tk?k3#8LE(y<`w~4kI0Wy^vl$3~K`5Muz}rDieb=AZh5LgAg&zf| zls)tee^X#bga+y4IhW}_*r##q?a>XQY z7_t@W)0Ig~!ADe)nI>A~Q&4quhil0FX4r!VDuw6Xc<==E3+SII@C`x$zBAxozwhDN z{~|n`oy@KN2jvmQzW~Jg&2*;20ss*I+gSkvM<)k;Lnk3yE30o)i2ok6>QbFiLUKj+ z&7ihI4B$s5?D?e^O~BV{pk?V#E^4L1uLUo^*iKAU8Db^Piu#r_+NMN@eGX!oWnR+7 zz91#n^|YE66S{4_Ftf2`g<7xfd1`d@_PguJ`|8g9%DX2c=j-#*laN!!!w+^r(67I7 zbU+a*D<6w{(`cw(xCM}S4p7RbMV^hOZV3mM_xJ(_Z!1Y0RvwGXyZ{By*nRpY_xS{O zrUJ1_qEOOFH}}ZCDfi6Wzq2k6#D6dB zJgm12z^3U_hsVAs?MD39dQE|pCBRgdVd)b0wpvaH=R;olm>UFv-_R_jxxFt!mu4ML zLu7M6x${k9iV{AP0-?!UULyvy2Chm1s3*AN4}cQEQ61+vUWSW)wb5ETVeV9UY|M+gVFe7W*kV3ziE- z=Vd6=q)zGU`aBx2+^RHzq>;*^LG(U+)5Y8>W|N8{Rb`V4rni}NgE z6(S)+%`r@33ez_UzBW5=+Hd))i<&zs!DN7C~p3kSg0H~ z{G4n0!kT|Mz#uN-K`t*Ag_q{fSxBJD&n2a{N5Ijmr9DMt>mvqiv6F#uutUSrIu`9b z;;o%H(J&4w8xCT)uEYH%$U+52<6@frs8=h+B4KAb3?^oJ90MXtH9m^px>QHoKVIC3i) zJ_l@CX#Q$}LM^IU*uHA1JC(Af*Z15uak!ksy^R1qCP4;_aR-sMrBJIX6E;cIY<9Ba zIYO0@$TLD+*E@&^@RjsFN^l|_`UX;j!5r~y#aYh2stl@RYQMFGkD@n?4M(l8K*kBY zfs?_K2*E)O8pgTUx8PltVC$3ruR7RN0-DNB%whxpi+lx6i7PW zxJ6-NbyROGqr7@Q2=3!`+6A;+hiTu%)b|v7j2oYM=VUQo9AjM)hA+&J)Qc|mzbsJr zl&E}st7Z#aZtAXoU#`>Gxv4=dHpYme7o!?l0TS~Cgv!tUM5YZuWd}WzAU=ZjF%|Ge z)H{QTuY)i?4-sc$79O?x;(Js)dH1AvhWdn~Q*D28=vSlp91_15~92v#yGobN0k1QBN(Igk{XPRQO1+(K2^!pb zx>O9`MDC_{!{8mT2FE8o{0ASYX{`2xWHm!IC6DFq>IJF_fRzU|gQ_;IdF|b(PQrt% zb{ieGKOBTJlwW8xmZ$rvrNJ^PE=~{QE3{E6O;E@$0%2&Eq9z3snnKfstI@esf zRS!&qHRnAw#@S|Z^-#%@?qes4yLPLyml4#W{}=JrJv{dKGv=8a4dv)Pk<%L5J%#n^ z3%h@O4tLEQiit_O-v?%WZ_YV`y6;hIRPjfvHJ{l=Y=8D$d~q?(89%4XiJ!2w3O@n~ zq>x|M;1@77#YMcwWSTB1Q>5ed%-w_U-@dW_g*SUm+!Novzp^oY6Zd%ke(yLq=(|gs zJ30|dIQ{3=N3_b05|SG7rz~QLRgx{(UG*VJWe^Vd8Gs5Ttd<#E~Fs zf=+vfy}?)VG`sh05uCB8Q*l;&3a`^E8%I`l1~ma@CI#Hnrsw0PWA_!;aft8d$8Q!t ztX8~Xa8yEc5!uUbXrf4wwhoe%jaxUe{tgn57w~>Y%E*9#LvZB-ZKKy zjX2X8j5uS6&-@AerF?Tpt{HlqzUjeJm12(MZ;f8rC#Ns=!^P7T2e=e8)MHN9r1T?Y z;Yjnh#4?!vG#0gmr}6bq2FivHd+IdG3k$hMX&ok4#tN;DN{k)SKzj1Cd;;l~+%`;o zrv^URzLB8o^g2Ten}wr7pfO}2Jq+u)+UzhF>*WbD&7cXMr$`f(M%9eVvq!|1;xpMq+B>MDjCvn(&c^b2sgzs)1%or0^{lDC%q7KE28i>o40gc5Mh zB$>%<;RR9lT3u;IROA)yagityQ`Hc}q(wAnj}I7WQzEo^2e>DE6srxYSRU3L#PVpp zP#P2y!jW>}+-{>nPDJ5JJ&j6NhGJBYr(5&MMw}}VX+Pkaz>jyhc;5lHlOm5Bbm{t^ z%Q(~vM4t|Uv45K;+jDDh8*9=J&A1?QOMzc2nNHzN@@b4u6g?+BTLvzP5fNBq=Poft#madmOPOLju&{O@d9jX41mgnvWhxIigK+&d{K?-TDL*{>k$rCHy*AQ$J_ef;zw!Pv zPB0y6RM6L+G9;qtUMk3_PP?D#i3;>f`1yuPIEFL3&%xl)d84BKX;Og`;rRx>Z_UXd z&^Yz03+fN#7hyoRfZwu)pBQ?9t-U|4VLEGEu?+6?m0e=D?LhXK@{?YuJrdIt*8ht3Vr&sH+!V1Hc#B<9^HDJNh7ok2J!}%UjEV;y!lrY}d z=S$j1$CMXrlaus=pJUAJS1|Ro2lg@jC^iduW3c`_gXBhPA&zztrpZ_@OgWKMhk7p0 zLD}39rXe>J_#Tqi`jOI!rD|TNKKSRJ4v48x*f`ilUAadf!joS;hMUWLVxSEYCsOOo z!V{8#(bJ@OXN^^7NhKcgZ)6-1KGW%WpFZz+*2vgZ(dT*aE54wsf8(iCV@9K^zo8w* zH%~?Mzt)YvipSq-$HrfD)mN6$z)`(6F=Aof;WjChe*~*V8@NoLD3Ef1UfFajvDPZ< zxd|&4G!yUhZltTXe2J!MXMrrF$x>2D@@9B ze@Rkuw4W(GaNQ^;%Prhl1p60Z5Qb7TN4_zCJm?Rnm<*GK!qp05NuK7H*_ex_wRY7# zQwkX_D>|$k{mKVInO%xVs&-HWu46^bLLNDzYln{=*-xt&Pi9n9fBm(L5NF(yyD=VVt4|c7GDTyLmLht)vTs|s-W~3%Xg2vPg2dUEn898)2ksb|= z*X(^T(y93flF>!(7AE)g{5m1rWx!aV>s~yU>t2@#D_zW72MS#Vce^A&`$#Q!WgnAe zy`Bd)X4IJeqBhba4tS-pd;>UYK{5YqAuB*`@ z_&|PRo?bPj-^=a;PPm7gwjw}SSvh{qCc#TN2yNk@${)KLb&okW)#3PJcSv|cO5Y{q zln`jxr05g~jN@SjZR0FU*5Q84rS*rMjjNCnjdSuA5_*OG@yMgO26v*zw-5XVVgCqq zx}GQS5yf<_rj;Y@{zH+&Xs1LtdcLrN*N11d=f6RD_{k9^=x=yF|Bd7ST7>$~5r=<4d4d0Kla!nd{?#rq{Kptt z(l6uZ<_bW2$knG&Pqh0I z)DHUTz(%$E=-q6j6AyxVbVlT*4SDynI|A$naFGSzgkop@zCJ)xYsvlwK+OJ6zkV@F zT(HtQNO8I@r#m3|Y6K5%btnQ8~G8!Hh>tfLvBg3|g_WtP4!gpFHr+?SO;Oa2Tc^58o(ZCu+moPjw@x@a~tW+QvKQj!jB zh=)T;mw#HdX*Q!=k2OG*1-DN+K;-h9GFZLcI*H+zg0MTa8^sX~ok0?&@>~yr%0Sj6 z1;;4Ny30HCJ~Dk+T}WNvijQRD6{fL_+wvML*-`1@M<~FIO3O1MUr6!#3gd_}7%7cN z_IIY4fXdd@(V!>`O-j1D!$H!@+TQuEi+#ziOA;;PfedPFnwi)rXl-gY@>+HKc9qdg zmLBtg%Bg49Qu;$QuWA^1`8okNUx=WCwm<_lqg{eFbFfyh-q&haFLK=NvtC!8z7a&6hQ5XJ8E z9mqf&39-K!lBi}dVt!XTyCssI_wU;xbFl5Lu(q3As9@g@zy0Unqb; zEZAZ&8$(Pkk%w)>+DxPam?*aFi7&!}@>{;L`EgvvA&9>+Qvz-abtr`}0^j`EkAH2b zd56#>Lwd_qSJGELDqiWZA)mz&>j|QVSAQr;MnQNMddC20P)E8%s0_!@v zcb(szB|#c=&?)ZK)&>h0VEOU4uGMy)h-VvVzy#y5yB81TX`3m!!oeGjF}+d1P1Ix- z3FS`zQ%cnN-jRwV9=4yWBlTL>Xs8s89NinHb7{Mkz~RV0^5RD@Hw21JfnaVXVJv8m`0l!aaR|88WUHgEO(rs&^7Vn83T`uVId7@LK1Rrn#QM3 zNpbyC^9P^k!{?<5R3n=DrFnVuO(O4M$N9V?&A9yOpL44apkX&ikWdvq%1Nz`)up}w zU2XcjsI4r3Px;_hxA%|z;N=7EW-WA+OQqCSDiDm&uM^Z1D(hs!$hhC{ef=Yx=S}D9R`X{&M$TVq|4)ZXBq>_*xj3>CfCrOD`^cm;37)2`7L;~m zSF+~XNs!tO|A0;yMrx}*%0%0YPF$;f?4dZwwdUdUG$;P?sm_5rjleEI5Ch+u4EHwj z@E-J|4s{d-Yn_y!s+miP+a^VtO;y(YWd=ePu29@XXrV zP&dzUMVI0a(YDxW*%il@;}Rph(XwiOGK5 z1tJb5fla2wO?%J83IWxt&beLJGgeh$15DZH_XI5##>6n#V0#sV=8$D}!(#_qDG&KA z8q0tg*vI81u4;nOCtxOGjn^G>j=scq{=3XG24DVhSzD`--S~22yY(z9@z~fPew*?9^fl4cQ^CwrH(E^H z4Oe2$*Ok<4i8m$z>6tv?5yH{kv_)WAm96c0WASkk*28YKdv9 znrK)iBNdjxz7L1(jP}7!_U-{64uR#?H*5J0=+P-H;;`G>Qh5+}M6ELBGC4F9O5H!}h$P(3**V>stn}i`m&klkZ`;!+UXNz5G zP<1;B#WD+w0i_KUbENHwX)+JX=c&8K;t-sK7l<>7WBD(of)ylky*>*wi(kZzA&O@1 zzxHJ%OnxQE8b};nfET34T1XVt1!$UC;N8Qq@``W_U=}_j9{9g;V-Iu8(e_0Axu<)I zv_C9+gKu7P=9FiqKr)5l3`hk^G&&-ZVp^#y(w9~hRi=oDJissDNm+v0!r9`L=G{I0 z9Q#b&Kb}ZpNWkyOop`b-U}}sIHOuDJmS{S?AkUz`v%|}n#mvEL$9tO_e;ay5MBAkh z@bxcxBZ`e6kh;P$F!$#RQ3;lpw8GVD$Q}~v3M{J=^9 z2p+IQ%;l3?8PyNin7SB_gSt?Fyigz$6_6YUGEx>Y;miomP<8NLG!K_hNmggiE~J>W z(TU;1!<4Brx@Qp`nk^ySBzUt|#O-xYNZZS`d` zJsGE7)v8if-_}h&z&JW(7@svzlJ<=mJmA1Y?@dwsVvGajj{~*DQnD;ho|TM`MoNJd zfIpS|7eEM>tKu(Fsgeg|f6(Uw_xmPnf3p+uI~MUf2k|=q@jC(WI|A{$9oo?q+Q+pMwK|sMd07-(p&qR$A-mBd84_xjG zkM4lL0_|J0^bG?p?$lBD3#W7lMolgaj&}@veMZ_qST%g~UYkprTHo|nZNow(BK=2# zM-D6%0z(2oOIICVzDz$nQNXs<4V(qF;v&F84nfqdY3(wcBaBA6TK*18F%uRA;ue16 zl!Z^{Y;AcxACowr6I&!kE!`UC%dYbLss+!?K%vW{0%q4HL7Zh(S3`jTV=Q&v17iGL zRy;Okhpwy4NcWGYMFK2?8k)7n?=~5Eb0VsonS5$UJsv_{QGt&PmBC@99JkjkVHJeJ zHxTWcJnNjox$cmhT0RuiU;=+M3nCc3d?PiWj$gRjY`|ygD-63t0vS!GeAV-*g`Xs^AY_hXr93~#@}yxHxHgH z-gq-^^6Y(K!mPY?M4ZpaxkcjC)tnki5|h;MLx|pv+x|u*q|SnL*SxLAVN3!AAOD26 zI&SQL`#>ukEUIGuI2r^b_XPRge*HHM=6`_hoRfB}{y*tJP(P}s|Hg0spVQ=jm3=Lk zpG2Va@0qFW_DAC204OPPBH&-aQXqktaJ7*{YZigaqKy6%q*!BPCgd}+q%NJC*Yw+e zJ~!-Ix5XT6qng&KTQ*V%8-zQp&RG# zX82ySZoO|;+ut{E;&R9fXhf^ybX_)zScJOxZ%82c3>T90FY;>N7_*)iDb6atJ{Wkt zrzH$Z?e9i7-nUw1Jtrj4y#H+qAwTI6s4bv${jKHw!a>+Q-2deL@(&|m9w_y2A5jQ9 z)56a=j474-KoZD(T?E08z1u;uzQrPc2@LbKSy1q93YLGoyT$)N@cow@mg{kL`t_xd z^lwsP@*IP_`>asryf-NR%yHzNCQ1Kc-pZ3pQr?qS5*&g4qeiM1&EzEp;bn+LODN#R zgc)!nE6S3t369gXku3+~G%-&gGbC<2epO<@PHk}$o3mNyCaytRFwRF)L(s*?o~%bR zHa4`2g+kf^<{_>!m|cEPirBe2oOFK$Zo}cmuo)>~ZiT7X=yfo@2DqQ^*X$7BPV1Ad zqhLdovxzA={Hj5Zxst@anz|i_EncXPKs#J_HyR#s;qJ)A0-axv=EIkB5g#oOxxexi zQe(NlBADE-pouZj^IP43>tn5Cz`@(t#KBY9n=vzMEm=oa%Q=@NLyl+5k*+!BV;WkL zwqt2l#<|o+WwST%R$$J+QwUNPvBZW3P`x*tzghTIC{VA-l7-UoyfIC}=p)IP`7`wH zDU7_V?}#6cZ)Hl^CxHy8n(;2OagPAG@4_#_6(_D+@IqCGWkgL+5rXsl!l?>INxMIC zusQhHHkA*`3lGA0(`w;?uryOy!1gxNl3H~tHBP?=?J93?AM!nC0fA=z^Ym)G(N^Op z$Mlm*vZH4f@V2lP;Tk&>`U34FMFgsLg27R`fD;y$K6qnF#x=w}1x9xh5ujimI$Auv zP1Z(N&W>g1i*=H_$xuss-J-?KVn?VKH zf%B8wP3N9?SlFEgTy9N?6h*wSO<2#A;Epm2p~Nv`8*%+9pofvy{1g7LZ%Nx|$#dJB z)~ZPjhr91zK{F^NT4-1cu=om^znYVjhiEoE+L{^l7Ac>v&$0wX2UR6~(ZZtd;lamY zKX)VVrY`H@^@$kIjiMP3WMOmfl&Tdshl@= zA>@59f2y;yoV(U>B2PzauCFA?JrjkHzC!*uFS-d@qe-5w->qAkf;Vs2Le${LQG^=9 zDykgl(ieIjSOs*uXjy{nC*p9y1_aBovM)D0SXokbrVpa8)azV$8^3Skg0Ljfq&{YJ zM&)s-yOpXGZmT~Cs;e|+Aop=4JEKnE*q%eQ7wN1_JYRN5A6Fj~GmrWBl;1xo+Bj!j zYK7FePhw%?x03<&433^$O3Tn)c0O`r$$a#_o zF4nQb%{%-MM(B%XzRoihS4KvZ&uwhpKA6}cHS6x3B4P}+ltvm?Z+oz(M;*jPJc5C& z2axheRdxm4K+nu_V(#zo@%e@Q(DF7dH2iN0KYtBKwSor|>CSD+ZiAlze|Y=f6laIW z;OX3$1a%r=Qk%9bUP#_PD`P5FqFx@A>J1Qs}_z3 z`o=+mo`LcyqiZ&M!SYU$Q1cqKNT?Q+r38njrcPK`d_N$+#ucf2s(!2Ej)Z?M0Ebxk zsDNjxe+=Owfl?g@#k9|u$`$%gNECV*XO|x-vUbwth{ej7HO!l^tElFBuGZ!mx#7E7r4f{2r#Z~jKyReHBl3MuwXGKWVH^F=b4aD z5wJWu_0)#P#tbJ8>h5w!Ass(D=#<-CRu7z_K9Jv)B^K*A0C;unR4#^-7Nhc(kAWt$ zTUmKzN|#5Tqep6$E1%U1-7<$8M&M$sP#8+mCJhb9%BUE$cs}8=WxaLpJ5VM?m zsVegCa#XE;AmqHDKXBzD>MdSgtXx^)rWv$j&BKwjZt)BxWPLKtO~aJjg%P3z)EC++ zOOV=M0C$w8z3F`mqMC4eT|q|}}~t|;T{ z&4g5E+*7~YwY~VciBP{uilp*YyG;~lkR)LUe(-Wk3p_tPWVB3 z+0ceB&8nU#i&hU|Nv03RODnaOBqyaFAOkHD#s-i0eX_bdsA=((_(s4~fpbn(3gvpN z=nUApgX|O^j$b{Wc4F2plPYdUugK|k{?6qm3FwM~aqFge14oX-M^*%Ej z>&yJDme=3!|Ac&h9MJ?4il7hB&L~3$RF{zb_M&1tEX^iPJQt6zD8=4@w*QS@t9YdW zVy6?}QB#*bDt7?VTqtm|QGw|P9NqZNfyUUwuj`hq{@@~$?KPCb_@^0%=vQLf;I%lZ ziKcQ>N&+#+zle=+0T0y$Xz2N3#(U|p=19Q2>5_Eixzm?Rpa8&v&An_GUgii?l>|-@ zo_(F%HbbsSZ$cf)07hB+v>2wz< zIf)7epGq`u>U<1cT?-w#um@{UmL^3@7?EGBGL#d*y%xr!GqWIk`oRsjfSfjlS*_-l zsp&9=z%_FE7?#p5a;wy-x~9r-O$~i(Cz;JZhFU$i=AOG1+It>wt}PUUJWvN!g&44< zJHbIxUzK$KrM#>ttKA0WYd75o08}+fHppk1IFEM;+9B~O(2s&47hH77=5;n_%~El7 z5}p#H4`S*YxU~t+osXZVlAkAj{i!bk@~D?w$h>D4Y}~J0Zu-T~2V~y^rsP0V)D^R0 zJhOF5`b@%1`%bKF)?zNdP(v)$2~GAK1udg2V*-@#rjdAK#xnV3ah#2hRZZ9KZtI~K zCK$3bW_R?>=TMY@+&&-F7e&H*J*9e?weB#g#lQV8kCNsw4&j>dey@?5B zEk2M;J(g$qLs_TjceRhLM~1r4H;{!d;u?SOE5c>jfR>zBPQi2| z50VVLpqF8b(4L_$b}`?HrMYn#6dYTCUexH{zI*v2)2LBLG|lIR0-Vkg${|`OxM#al z;tShzmItsA=8w_5vfcn5pRJN2&uI(3EJFuz&?V~ z&w6y8bm^5Z9(*YPecN5Dbj@%Ed5F9|aP~IOO-b}EcQcMF9p%lgwLw|g1xDfsbh#S< za|jK`G^d`D)3uMMY#3Bj%tckyiLSP0=qlZbUG$|JqP6A9Ehxh&+cUtj^!XZ9E>-Tm zi@xq(`?d`-E%if`#q!7DItX;Mgw5gjAR+yYD}zS}$`0%M2c^TOOE~PDC!$?shWpI5 z?{%&KQz2^a$d{E{8Mgnp;IUiiymqR3yTMcl7Ch*%-w6Sjmp_7ErJ`uywQ%Rrm3%sG z%sdt?-8=gR?T8baSd71c)sr%4NUs)g-pQY0$I!dUMSF6=3(3Azw$u2h+qy-d_L^1f z(UN^R0Fa|5Yb?0+_s7zY z#voJ)?1*0m>a^#T;+z|xyzaVLts`ZBc@D?Se#ymNePYnlzz=c6?OxSeSvJ_1_7`0D zHS_nIPTm8m_ul4Nc8~F-+e=*&JtKL?P4|QE-mfbIK~(c}pk{iuZe~GT3`;hS8I5D7 z>CYm?+ty%YU&!IBtK{|)HR+b(YgT$tS{cezw>|Fbn)pk6FXREUF)+hwoL~CRfng^2 z&{)F-I&jOcLXQx0p9n~w3WMsidHJ5`srjcCaDO2kW<|Czim2H&yDZhNmawc!RiSmB z@sz3L_bw8onf$9oI&vmUa?;pNBMiHw(}DjXHJOUnxAj=1-byO!Mg1R?pY`+X9z>q6xw_1cKf-|7Eg!JIja zE!&04!mv1`LzH`w!_w@#ur%u-S50 zh+dh>3PFUN5i2;ur9BkAF0;!PM0*1Xx`PEhu@q|w|NaHnc-uXA_=KM6f}Zt))5u~e*gf3xPTEfvKr{GwRrs_TKL{3$W5Vh#cxlXx{q@B2M2QPG z^*suF+R{GJ^e4sgn7W%e1hfR$E@R1Xf#PTw$9rB_BPj**^oH@=o`JagAYZ*=_MH05 ztTzAH}%?$fpm#Eheienn$9eh7O zWI#f0OryPkgR1jYlsC}|1tt5w65Xydl z?c4~t_(w^iHQY0spGOh$HZ%jaO%N`lSLof=LYKxy*A<%x(ig!8S(sx^{R7qP-EL!m ziD;U$X34VOPn&E3?1+sIqkN!<~c(6U|wKfOWUvJJ@q;qk?18|HImPyY-o)rAMdmIeY}4^Q`<%2)Z!nBS@38u6&R|XmanNrSDUT^9*XeWf zdQa^l&9E^%-LE|=?ZBwVg`JfNJe8%c>S5%jX1JVVDEgp&B6Aa+o1vOYK`ohW~s}6Ntd5-Wu+sd@V zX)1EP$}uqQG~&5n-)v0)@^b>!&XJ0yJqlLuxX|yc$b7h?4ngO z%(Iy#`Ie=^eDN=&Qz&h%@Xdchvl_vh9KT*MNN*s}ZrsY_z~uG^k5aQQl>TuWj2oP4 zXc0h@F4q-UeHsyV#B*|xkm(y&UdVCNXGYqs$$=Tbno-5#58PlV>C(p9NywWesfAot z*$by;7cBou2xrlC3#4ag+mB+%Tlbq=8P%}-P-|<}tX4mmkG_x>)9zFr(D=7G6 zbT^i@wz_R$Rr;iKN?QW;^P8bMg|;qd_f8J{+Ktw((zE=_L*f^ZVlXp2XcB&iirN+u zfzqVOD~#lb9N<1N@`^o9H@@yT{EGc9fEM<_egO-9dSF=Zors?@tJ1bqM-8hTQ#oB6 zUfs;Bt?PaZ1Ol-X6EKlfINP|0X7KgJC2Ke7hQ|2GCT#|g=RR%7Z0 z6QwfIgm_{y6Qw0Nb(F&r72HmzEa4Y#D4Z4-u@FUm|69Ysz)>s;ko!85U9Z_KuN$tM z*3RmZ^rIha;ZCj_;!L_Xj}OFU?k98m`E04I%*e~stvXQQ*n zjD*V9;yJMJrd2N8pe*C{8IVR||ftF0nPjMw|0#Vf`!;+FfLqt63 zzZ{(_$NM148PEDvxYRc&I(>`gj1xQ6(QeTnz~5*)L|XJ0SNes(s6Gku#P64F6Xd+< z6W4v4meBENZJ=W9}UhI3-XIm z%T!`C``MkJ%EF?)P16akeW9nmL$lm91uq}hndFXZT6<5t>N=0QoW{UlVlcYxd>3p; zzMi!A3PNWNf>jk`)pcV^V5O+)#89XunujliTZXzWrCyp{%`mP^OWb(Zw!fp3wXUD_ zG7WVS7|f_xdm6IYQacNUOiqw$%A~dr!R6T9u~Ak;%S<)-bJHJ6Q|HB2mivP{Z*p`H{`+@w=vywixjq3Bm4tzxb0wVlhXGPf1*_54?RMgbi{{J?Nh|%zJP&G&U z&i2{rbZdmlgyV>>3jhNNCPl(sNPP+|zvVTatITJ2Mz@BLQp1t!I>L_x3Y; zbi0e+<(b?6^Ddn*a=t=PEE7>DkhTT7o-SOXPH!X@=npuNaq8L*-B2MgFM3}NA#0Pw znv?`kHWH%pfKhFr4`c8dAOSsA)^L$z$d`zjnKn?s)OLMKG!GAy%9M?R-JTGXhuO?6 z+wA<_D$v}VgviZin2X-tuBnd#ZN z`7E2cVs|H9G%jl~qE45D{CHI`dn3&RM0Kt^BE3G-@y>GzsZW!Hh=6Rh(4b}J0wBd- zv$BrxnbwXw6d55N88ovQ%hVT9KtXL>wOd%s{*&6dx<>g@mi_%$GkSqEuy?u9I0fd} zWWtEbX|ZJ-s6;q9Abw~iw>2`~&}M3^R$6=4lVCIT3X zL0&3S6mkUr;*?AytEzyd+tymP!1OFNtD1Cq`EzOMC1N0aTdzVc&|Xr!dUM`vd>v-P zS7OS%k*_%sxn6?R*ugd!?wXdK_GocJNRF<2o^S~0o5K)>Wf4xJKhs+0>}Yp(o4R23 ziZPLGG!CuN`coytlQ#-zD~UBoHFgWA`#r@8QzX-91i?aXpxfQ2wXz5wt$!jrl8=Z# zYAD<`!)iM@W5GAwv299TErraF+=oJh+b;q2m^rjPKnh@eKWIu9D=3}bnWUSm7q=YdfmljDQ8PZK=u3&o5*?7HxlAj+F zC2*swL77F@%4PKWAp)DIEJ=AaS6NOOS7saHTZv8_?IImDRl7wJ!>^Ti1uANeVDZm0 zhnL>N_EKkJkR(XDSYpu`UZ!IrmAF`cK6$ca&t2J4bw;sGt}GA-o$kO)4v`5j^ND0g zKPIurj!W`x`{?La0JdT1SLG!p7_;d6Zr43;-EAbzGt+o0m{5%A>T)hEO=jR^MkvJE z1jH!uIvG>=f8Q)NzIMdf{}!K`BErf&`OK7cHegtNIK3?*v_2}?6{pK)b*Wt9(_*=2 zA~0F|Qzp?ndY>)lX1>5#(@1~O&Z?u*qEB)NYB=*962tg+aMn@2@=NHKUmbD5VjVit zbm*v&(%lTE^GG@IcebPapRCJhWZnYaw;=Xh^G%PFV@Kt8Q^oftnY&~OhW<}x1`oxX zw%7VE^2yb_J)N<^R;7L#rd8OKSe1Mz&Lazu_^@X%&9v?ltT#M?#z~qkv{i$E+hxJV zLiHXHKU=BeXN){mfNsE&?mHU)iE9nL3CZ5+SUt?-9sIy%(@2KElu8L8dZ=$5QqkE)aBZCn-xuMYL>_i+t?;az@%aif8@g# zC4Fk*ZvE`;qw%g7($1%%tgtf^6>j#YIFnSK5UL|yI70|b_|6Gm$g5qlA6ib5B0V7| z&^d^c`bU?epA;)rs_HrF*Un?bkwDnF_mmfMyBPni@T^w-6(IuGSa$Viw-7IjK7(ZK`gBNd~U6F4(c&L3vA~lZ}85&v7k+Pxk z+-+$jaxYJUd%=eSQGxVALef~ma9Z>yR(_KNdxxr@Q*={wQjwqG!@r6AcN~;^H~B?B z2f^?0^EZBpBLmsNUZpS{iy>Q9Lr4T;%+B;)($;)dkGfoM_rNbsY2?_1slUwrr;`1r zl;JALK@3WezgVF#sG_ZtZ$V8l7TYs_)g@XY)U9eS)se$QO8jy)W>w^}GmS{<~Bbs%FkyZlsI@$%c z3-4}SA0&l;o(o3&`7RNIXt6`TaG9kY(umC+iKuV)fqc0p`k@i<*HJVIDxBbR=^o-j zTnu?ReKS~mv9SfF)q<>Ml-OKUr};dwrF+dCfS#=wanDtp2lDxMpk#cESaL=!iJoPO zPC^FbaxHK&!EUm$EpRYzVgcSrS+oq>2^P``25Ow;$%__hDR*;Ps&|>BGldr8FpAqr z#3_L{Dz7~2nLL2*g}ynzA#E{L(%)~;4>iy?L%?e4Xl!$Ctn{xCcI5$!n!F$q_z-G8 z5C1&*nJEAwbf!&{Jgya|&xy?ex{-fs6NtRg_ROY5DHsf2$pnr5V!+WR_e2BsTO2o9 zU(6T1i&Y&<098wrnphPwrQ|oYoLF)sQ&LHOWPzp-nWo5MeT10<+tBYh*?$RaFbaz{ zyfVe^IVT5V8KYVTq4sm$TSZRZxzu;)Y6qiDh_{Mp|74@?_~}YOw57?KvZO7+rVFvP zg)7SeD|6!7G6)OYp5Yf~N);4AD~m!Kf??$Wv3EB~Pe6Rb6!OX_+4*MN3YlltOTxAD zgHL=L()J7NAHVp7{R*z13^tBccesM}d-|o+yG`kE;g(iU#jJXtuy@ihMP=4w5kHGy4D&#K#r54MX9X9C z!qJ~Ci!aJ16{+kFW6i5#7FK%7Emy|1d5soIy)kp|Jy6*nHMUQ`*B%(&TJi=0U6U)) z4_2?PsH?ZNfN(Q@d(Yd&&AXJy2I=&O$(DA7eYbJM0~Z+E&sMhCy)#MK6;37m+Ww(x zzI}Qo#t?U6QeDRE9oFA7vw`y!(K*id1PA_C&+H8Xx0s_I-JU7ezA$DK?+t0=9;N7B zc=Fy~UjB3wXjh3pfB)Bhnn30-XXD34>GA)&brZAuZ>`(4 zx|UngD3-7IX6f_`;Tupb12NZK%ZrfpqJOo}^j7ifBsCcs38P)7U%HuOl5@F|PF z)ONvn!zhD1`2^QZN@pM=N%6J7t@}dm)@$)!*pq`pE*8`#l%>7bA`IW-3=hlg$CUTS zWaBIV=xR_$-)6`X;mcj5KNGqqe=jvs*Vs7!gfU2t=!-jTf~08) z=$3j53qT<>bGe)zc=xe==lU}4$?a7PyyKHc9xBcw?if{gX<~rT zoqcs~1>u4y<8Koz$>_Ww*U{J~O8Ix6ElOh<9a_72?E>c@S@s(}lYU21F83S!E} z!zCqahO9evDduL)t5?<0Eg!OvH!*X3FrJf49Z?(KKhszb!*qiuc~ZS&ljAz}Iq$C| zK&^BPZ{T6u1Fb$_VVW!Cp#437cYQvN7+u4z_5l_*b9YIGjEwX`M6Z0tHa zn$)OHJt+wfH>1_){6kw#Oo1J7YF{hRYZ93T%t(b%3RpHU1?Ek^z5-5GmQ zAUNzt-?LFa7)RLhrW8a6e)6|1c+wYFD2$+)Iw)1?RH8c&@dEV7YAy)HJjv0C@UGx* zEhUfY)>Q#bPIfmdr`B&7(WLRJOPyv;ljF1zBDK2(HCsPfrWO7qBd#o0BxDR7k9&>> z_zy%y*Ai64;uVsp+EFV$^|G!fOxjqTcjJ4i%{$~{Z6Du8Y1O#rVWuJp4!3%7-ubb0 zwVA95=`$wLvIioYd^`k01T}$R5)*Fxf%k}(P8BaFB!vC|b$)AGN->_5L&ihiK=K+^ z3|hm~mqJps_PNA~@e;C>6g?Sg0*Gc(Wu}Z?$Kn3_vTnL3pc$}a?35Wt4bKi+q~nyD z^*@D)Nf$bdS5XdXJR_sa{G$+SifYG_luUAU403U;YCf_&fAC(}Phd&UsLFGUZTeUX zrRwod&v;_wr_SC)p1RXrcXXof&ZNmD(laaSW4v@I*AYuz&^U9Af;2;e2mK8o^`&QQ zXjn24zXR8Xf^pi=1&Uvfd!qrQ<4LsWFr1@i2AV2g*EB@-qrl`MMv0^$@jf=ALKj!OH0vYKC6xxw5cG@ZI+XpJ zS05=U6AN?F4mwf&ROfkSq5TfpF57C7^x>szMFW-;z0mujDFEXbqY*kz5jTM_fr$vY zX5HtVf0$&IU^L5oUGkH+b(b72xc>q}jBpLRHQdi~YDM~EI0vhIbTt|EVD7d=s3QI# zm_o!<)NQ(i@|9$&wJrSaux}gQan+vT2 z=rw5V`mc7ry+^zhEoyRAKx^EA=Mki5+RQgh^^M;1-lr>o;5WK}Nzd)Us5=73JxTUE zZPJC9z`IU=Xzgh0oY?p@ydFs>O;d45%0JqwCv)KK3|{FAs+}mXZI&=VtkUUHV#g&t zo(uz(`PoGxLXZ5f1ak+JkT>C8jxRIRNL!r~{_%oQHJn~mJ9D))HN6yvV!cJf!U@)q z!J7fOT1GfBOx-s~vf1G}Lvw50l23SA_>s2rf2hn?aBL1GI(fXj1Kf+&9Tv-J@Sn1A z=QyWS_G_je$@!ZWOnO&#NyJM+e(io#x<&}88O3Jfc&f>t(+l1E4Ms9k4f{C7Mvm_U zQIoriVRnm)a2olSm2z$w`lqHZF*JKnLV{R>^>vM zmDZ96tUfagT69{?rk?5y=dQk-f=-}!C~0q0wS#g!#4z6Zb_w_b#)G>O1irBTV6Ea3!-ji!TnZ=b}1~TRveui-Cb05d-A-_mU0l4lbZeg4c=C#F- zkg&huybnWI&6BYSWg>rKMY9{MNiPy5Bnm>W@FO}*XC+lTj+hFFydvzdh&+!fMQgod z&XRmYd#@+}W57n`xTJvbLs2RP#MSYnA%9%rn$*D|IHzEX38e$^cW%cdUa>9O!XYOv z@v3+xqv9+=^>NO6ZSrt7W~nV=iU=Vtu`TM-h)t8ow?tlWF*4HJvzDSBB6oF!OijCl2eTJ#+V;?>lrKoQ31l zp(lsQ(U5}(EC*Q^frMxpgoDh0H*V{_kib61K{ydZJ|e}Mo?{nfXaOcaz(GM+YJdWE zL9a$jXUi;Jreyp&FrORV?dV9r(lm!U$>&D1s3nQWnt>B^R}mc|)>JY6o=ey80v%W`;;(|u4~5UcfVGmXvhFxwvJj$5v+0cc;uxjiUlL)dgj+peTero(E|bo zaM=ojXNSr7%`h!T=ch|o;9m#X-q9jjOa+nz=`hu3txJ{6-(K9EcFWfZUsata_huwf zxcm|iEn{hBFL;4^@?Bnrah%?WpeqbjT~bxlo(5{a80_r3QVDTG=OOO7ziCXopd#~@#8C7z;3s1$Vzvl1ZBtLciPY4Bo=jvFVFwnrlo z%QublU!+Xj<1?$O2HqJ5!x#ouVIU?TP>Cc*`vIy9!*%|Ts!iQ7g5#tToKzWHr zUxLY7vN!I(=TQ6y1-PH`%TwdWcO&HIDq;Lz==lHR^W;pbW@l?}Vrgb+Xk=sh-?gR1 z>eebKQmA~{!LrEUQw`7^{C_kGWdjj4cafDa45#ftlO?WiT8Yj>@?rh<*WlL(rm zCzLCnIt3;ko=8Q<2C*kqi*Kj9eP;Q5K9t_y&ab_ITI&)mMU<-^!O`O z&}gUHk%@vDK=L2g)q;)+3aB`>-EtF$ECa0t7>X4Xhz1GA_;mdCnPb`aWthW8%Q?fi z4?X`6gNLjO#?w(vC&eHu2Ei-YW;Sz2XL%K*+L;h3{(>YnD^a9YB@}9>`3nzW^<#pTD~`Sz zy|#4Z6%tyhD&DI}fB8m@J(rGxN!|5|OVu6~Mi=Sdz4}WC?3{DX7-w#ArjkS664xpt zxxtQDq_46==9)9iu>8WjE~sO@;i6b7S?FlL{mz@W7|-oz5G|b=nnaWOI)fC~<2y?6 zU0eDh74REBdpywSvc4|7m->lDajxC(jM(S?W2i=vCL0Ml>(DrfJDA-#TF~7H&gG(< zCxwUUh<#P|N>m67Dgk3G-`PVD^Do)j{z%U2;(;Mx(fuu8qmb2b4Cq=yeIg+gub==- z_;~MeOUD)v98yksqqNLNl*l&8Pa2X!8%fH4J)prkR#fqYwTr&vP|dq^&{0j)sfLY5 zI2ItYo7stmX5^yw#3tI1?KRF8wgP*iPdhF+ykB9`F`Dp-%M-%lFeaeiMN>$R-Idryo+q zaSZj^RDHJJSkpk1k&w5o@Uc?a>b1Yqy) zMIzgRA#vt}aTPF*p1!v;dt(gFo&BHnUU5?SPsq=zQ|%`!>Hp{_W&W=|AnC{5PzZJO zdl6=no@OahOsPx#9E|b+4DG1+CnO|qKk;m{1az?!XMYg6@4sEgQ&jrrzFlV4eMIXou$=S)I&@c}c2l0gOq zr}65`s(Yqq+{r^O#)D3O2<7y12%%~2Ex9W0Mp%epSnh8jL_N; z9|n9!vn`Ma#?4`MfN#q@jg!W5@>yrP>DUCB`A}hN4GcfKSganK;E2%3zeOJ5)1{*8-^U+x%iEwS~h}Z)o-x#EFc``QT zIMatIqci}Aba@;--?>VW7nBB1%&7VnbKA|mS z(;uJ;9_pA#$31H!YfCrPCS2N(o=o8z4IElqiUr*3 z;oQhzX0DDP`HHw+w?no-nLDIF%8yU<-Wk>96PtBLlxuN7^ofLj=?ucv9mV=UX(5M1 z;!^T_64@rsmhM^c_P=a7w?^!j|09&r83hQ4{{Nuv{O5tL*1Y@=`=@VPE`AZ;qu6Oagwz_)uk1B!+_zss7@T1m%qLOJue7nPf-LL>FS}(i@vu6%jaC3 znWl|#OfD`XUiLR!udh6{UN`XHU!SK2K=KEpv>k?Kb-$i*Uk>RJ>>ukg2DH(o(!LJy z5pGSSF1Jy4CW*sdf5tZsfurd-_h%-A+`Bs}gxvc(u0p?rfmAJ*1Dc(8?ht$BH+8{J zHCL@nl@m0}7IF>LK~zG3n%c^!RifcosK4m+hHWjalv{CrNBL5yroE=1nX;B5S!2y4 z2)EBcLVx+f9VHc+1gaX71enXwU&s(kVS>ezv$vYaf{DZDV=b**BN@=E8Vj{@cDi$b z>5SQcuIgBk(QuhnN0*gxjAe6%E*qL08~E1_Y@?~1pfwF#T|Pib9M_=ZFFmJz1BukT zyk13uqZeLrMiD)%+!Q_1nZteukdSdH2r)1Zxm>yDXG7D$T8e&hv=|TVy?4IsVW17O zT|45RE;*&sBeemFY0~p}F_)n|lCXzkM4bUaWhXg(fEqVS>x}t>X$BsxrCsa*W~5kb zsf`+Z06l}X+xS(o>B5k=DC5{1u3D;=odsFMzHBx5Z@-|SRAe6i82 zpRirh_&u?j#|Em)#PV|+>HgHK(CEDn;*c2SbH_%sKRp848$gm+&sv}SH{+?lHnIvl z^mOPq+ZEC?8ZY3L>;%bSk8@J+3Y)r&YP61jUZOI?N;=X?lhfQqPy28P%`O;CnxCKn zuZCLEmAqx;g+Pq?k?N5ZKKP!ZQHhO+qP}nwr#t% z?#}&o=DyE2`x{Q4NJM4?kUEj2S$t7d2?Qpv_2F83MQ#h(xy4u*$;RJYKOq&sR2t}I zS|EaD&>+QVNt7++sL(Q_(tu^f*jV@e==vDAH~ay0rqo*N1Vf0*Ra)~+rOMGbE25aI zO>u(48dl(D{4;!x(#6Lz53Sv+`76@^VbyFtPHK!Jph;T!7pZ}G89~mdA8GNunh;|f zi2++q@lB)f>oT(iWhKVVgkxeQ*0lg7waPJy4p>`sV}Xpr+z9Z-d!_fA9=f9Mtg@O# z1pFbo-eBmE6a(>M8^r-ej4$@8TUvrW$&IxrxM8$w5IFi0$HsSmN*!bS1fYv>A7mTG z?Kg3yBL$q*A>Tg6x6|?*jD?94Zw`{kBd)idkl2D?qcDid?7T(FNxHQ9K}XQRUT)a; zNUuRUo_(n_UueP_5VVUy-nT_l^LoKPA~gK{OkJvR{j^hEQ6bGEuwEUgGp8vY;9UZ^~gDx`#h9%)Owe zcLm~K*+90SSMM8~;b~mt2EjzF@!9I57Ph&fw8HbZmu%VQph2p&3UmfJOU2qt^;XH& z>Rp3Hy#Z+&N7kQ5T!clx4OuGorBw1=U|jUj4>rS0*BmSJOB)%G__1xhe>2UONraS=S^(=2RT@E z10)y&;$NwzhF5vgrjrCQ#4*D}2; znWtVp5$LD~oo%7M&xYv9tGCgCfvER~F>U)=O#*v<-54unba_C%4IOs7^o~|N{!=gP z19#e};AeA8{io-_`rq@;f2Em3xplEWvWS|(#l({1R!-gTIY6S1umvypK)nVqsWbZ~ zBpmcp0~&c>Wm$fHTshHUPi*=*1iYEPtIdteTE};BGykwq*rO{Bn8GOB&k#m zFAdjBT$iCg@ggU#_#KC76||{Cy*inEA+`n4a{U1ynP<`NlXXC~Xp>rtk)xndAyn+_ zQ7ACcJz`Xx#76x?VWc&+3+q~xv)?7s{fjO6`1o{Xq4vk$5FYYXTZ$Z|lQeYODCHYS zT0TErXXTZ`^=gNE$1^B(m%>~J0lky0RqtW;i3fy#7Ee{k$>132LNIaolm>?wv>-Ma zp9aYhR`tZ_OJgXN5Gyg3o*q;+%h2E9aO=Gp7{ed;r-xc%t?dSYGs_=OS*A>!*ScuumU)-xH`Uc0)7+-UWr zRIE|d){ImHle96S%Zk>ubZ5ELEjof`MoY@(HkB<)wl($vnFnr40?Juj+#w)8elm(f zNQj7mAs7;M0egpsD8RqbD-e`~^oey7sUMN93>?N2#uBSw9Hs{FLd-FDic?-)qgsIbN<-T9gO=Dv;HKQKwB6Wbj*7- zSl0IcIM70<9$|cC#$>9l!09`jutB9&A4ft`R8bt=0r|!yGT5E!<5+NYXdeIGs0 zBczHo#ZM2%dxC8DSfYzFRr??gI=Jbi1Jc7P;2Ehk&a@a)<6I$;7DrJICI*2f$so^;^=*j?o~_Oo7wdQ7%em{Y8Fw!}9y(dahP+ix4)MykDz ze`7w3vfqwMN1wWypkGH`clYr3kl1F=1ykzI9qada5FdD~K*FJLJ0O#W`E$m3OPpGu zJ;AI2wqc|+gOtqkuR`?=#jD6$7`#164AM|%OI+CNEg$%3atxX6Vy2#v0b1%CAbsyp zIgde&E~5==)I;@*yu$7K0FY8&ibmQzn?j`{r9H7?G9Zo8NLHZBg#C@q^vJJCCAY2K zWu%+P0oTWYlVqA;?Lm3YQC71L06;4wc<8pV>x}~km>rVkE@=XPH!F_PbMiAKwv(s# z@7<>KHtdHtE9KVlFo#no_N`GR=S#P08%yq){%FvB5|%Mh810jasNfCN@{A+2=K9Nb znMfc7&EJZ`3CWT;);H;V5cP1yC9xSI4qjn9?J@x8nc29kSla>2^N(EsWql0nst}vw~WyG3i%kWC@`o5_eT>3QIs^W08sx@80 zQ4W082^YEikzHVP$*kP=Hx_H8-_qL;-Ss#3K$}EQEB_vtatLHGa|@=bKqb`4(&2q2 zHq4(C35*0}IgFAaq}?Et#URAXw?^8%YF+D>gI<8C*pli5;>bLr*=1oRywA7nT;*SM zcmMzhMCJX)bIau8uR*-0jV)*%ZwNjyPnzENhXPO}#_7kuHmQ|Ke;Y& zWS;>)n4NrB=Li5%8wiN^uBpGrTNLl_(be0(I0YFXAUN1oRwiSci?t0wU@$oiY8G2D z5}(nQ+Gc4%4_nyes+KvCXJ097SMhn)A2l6&YGg$P72Y9_WN(D%DIGPnvm&;j4OS2U zqUpysbx1q9KsB*QMCHZl53*m$JI+Yaz>xwVJNDn{Iqw7zMai!VOB0RVOxpG;dKM1_ z3bK~At~xCq-zxowI3rKTYwcuoYxdy#-3r$_VXp_OzqaQBCbQa%yJYfX6q@E`5wQ5G zrC_serqilHQ0z)bCm#j8ovt@nFBzLW^RtvDGJ*4LNVD7DAUSuLL(MzVP~rp zp+V51DD5zrIFD2Y+54xstEXhd`Xyjacfk6^#&QxQPYct}-iJX!pn|B_*Bb3-!d}tL zf+o#-SBj%Ii?)4`z}>X(kabQ9duv2yA;KW*!W-X6YScarym5*J7>1gBv)PTE%t?WSYAKE~2HjeepJ@zI)!kAv3j=~~@n&GJI%_G?PvVVdxzKq4NQB zB`1Z?BT#{ose@;WPm|P0G}*;(??$HC9TaCg?wQMNT8Mi; z9QAZb)80xnNla2rCvG^MmVTxRmG*Bg_C20S>W=C?Spy%D-8Kb~;x3f1H^>K2T~)16 zXnO+i9->=B0|_ap_>hlhwNYP zYTnpLtZHf}zhIz?sEgW0dvee*)PqJsxL2XI#mXoCk|{c+!ky%3W!@tct@X z{`8`|06ssJCCJrghN2^)aebb#OtPY@6Qch9L-`C}TkH_7Z=Evw>k0DHfq4-P7}&<= zqL+CZua1xd8X>NaQnoWJ)f)Dj;u-UT2wu92zp^TK@mh^CwyVp?^n5W=P6$GsyePBW|(=pz{+ z>x_sM{6!?FS9}Evem*)0+&T37EDP0{vRS4uR(scFbZ*XScft7aH&eU-Oc15u-+rES2P$)E?>L@MxCs_CFFpxBy_N#1Hsu{t!UK|I07_S0eZa z{wu0WV<^LZ4QX|(Q0m~q_7SoEhPMEKE>N}^4NMcKlfuxDGr?&~Az0D*@c_h%<$5j? z^E{EX%rB60%dLEy5t|XIL@eN9l=Bwy7D8gmtY;ny5H}w+HZtzAH#$mZYxn-TKll74 zt-lowtO34*O8rjf^Ft1GEWq2L#YgYkrOMEu`QRigcEIu^3g8R}JV=y^0L!S?NPxH~ ziwzsJ@BW3RHB=InK9XNHu2_zd| zHV#)j53=dEp)e7w^V00j9jwQ5Cq^MF=KX0PR_OuWmMBgCQ;-pcvIEJN3h8-MCmTJruX;#-G1SO z6weC@3t-zw;U+v%)u=O(31-dZP>Sb^J&a!A3I^D4U*+fQG?e1JJD~LBRR>DwoT&dcYVuP{q(c$q3RH7&Yj0kbG@l(CG6<6Pi3bqmP}+lL`~_K$n&)A`#UVoaw{kbOM-*D!;k z!dA4z5Z-S+*iNxNw9O!(MGY+U%kRxR7C*(<#<^nZ#u&{3h1@ex?JZ6C48vi*`6M3- za?V+z=NUC0M{IwPECGGJ4`?X-5Lt~=Ye^3%YfVTC;*c{KPFbr*P#JnBK)oxt`yIeU zh-ka#w*b=gKTi9)hDG}4e+tsjpUUE&3djGaAQd-s{ZBXwjGz3u^Mf7!PG@i0M@L^P zY6zS`{<9LQ@cgqLNqv~F$j`<&=82$GN>N|6gt5?pgh>hyg6$K`H=!m(sKXOWzuldx z8rkjneTUS;;9yp==L>?tfoBJ7z=uV|ISvT)Jm%JTL~c?SDfn`6X6#>6@nU1Mh6UN)`6(DeG}vgQ0@L?J zet)%z<7SPv!Mi>JsDD%4ms^3a=Xm7)uh^(Q;H3~(p9F0n2 z#7O2Xr;=0R-Qtr;WSIdjjky0eR+i-Q$eCk3k}1;LtXU2}?zy5B!1(19NsZGn13Av9 zhM)8|Gm$S*i(s3z19@vC2ca?wr+LxurCHnrUoMjIfsH4qBr6@ymq^m%kSiR4W?ZX- z{;fbo6ZMs;!@nETh6s*7daG4&U3`G)2Stjx(-on`HvhB-nSVShAOB%M-+vfT-2Wv@ z{Y1roSDFc$|6)9YwoOr*G?8<0Lp;hA-*XYU;lh#Ri7ZKDRQU3o=N$pU$EjB{;csDF z_XCMRLy5KAcBARDOq1v423>0Hjixg0GZ?NfuCBSaz5l56*kRgk%;xM?g|R`&P7KEm z{*4TJw{yV_4kpJgb*a$v%~ifo@v_U(E!e}TGWHr-3^Y6z+t^m!e|H5}slyaUL>-dL zg*&AJEX14UbPj68<`5FAz%Y6=ecV;wIn^$NzqUyXHFW#l8TmAIiO!jvF92+)dl zkx77HbrVwP>&1BlWKAEB3^LnQgkzdNa`>O~q7r`fuD<}qu^)(~|>73^6lxyc4 z4$0IkCZ4@uQc(J&2~FVnS{GrmKu-;t)C;&^l|A(Sps&p{_%V|j;o`rb`Ol_n@c^-F z?gt*@f8g(`ZZEgTL10g&?JQtLm5&2Ev5ZCe<>@6JU1LJ@i3pWr4Q!(OWkx=IhHG=~gs{~u zErJ%PA`mvTKJiTtBc0u{*E+r2t&fQ!;KDElX|=5#XkM6}e-!*WX#64Q6cng3-|}P1 z1>mh}w{QXF%JICzpT9((JDT$u0CzHkLNUW&x|Gh15IE8@d%56h*~9b{r2?cTHQBy3My8M{bw`E$2ZT?VyN}BzNPr=__L9?jsT=_=P~C4y>TY4>`fyaagmJYsjF)rkaS(-uJ9s2bbxBM1%FE z*44wPn8t3@IAQpf@kw9a(4{)ce$$ik6F9YIs%VIC z>e#X9Gzlv##V7aSpsPi2Yt$4fN!1lS(DS0+OuSIY&9v6>@T_w-jc4>G(>S%2r5BgS z9&FaOT8e_-Y2L?m1M`gTLFY`C%i(*qz(~rBCN1MNuBDxop$xaFYRp4S1~&rz@&-&6 zVpDI2)uDJl0fwfO>=6I=K+of1FD8)Oa}?ZjfigBGIfpXB2NM)hxpb|NoJW=_smmW} z8tz3%5tia1A_ll39Plu0BGd+InXJf2X)Z1rLxmvDfVour%9I<9lQPRMliNM~*ODofKa}@gGGZYy@n|uqcPc@5CjKz;NbP7xbIfDtdlyI;VbTd5y3rzLNuu``XRdBV>z=1Z&Q_RUQzRjAKw_w5ce9hv9j=;y0;oa3zf?&FW?*8BT(oGy>7 zkfl&^l*M_$$Szr*>2BNDz^=mCZ8cHY)|2a#YlxY*VamFB?%RE+$gP8C?scn;0fdVO z%P)^`_3hC-i#O`?kQZH^C@WRR`>B^Z}M7}p13YLBlJb?(^{&-0Uo1w`); z2yU;jXqdWF!8cXrzrx(kbKPbS)<3IxD6h8=S0B!iUa69c4>%t$(j=c@!e8My-v&zELuK zFyk}^+CF>Jyy z{8AzLzE-XAnqqJYb*|#}`<9iN?P_c4?CR+1&P+^KCKhI=7ePi;F&l{CLkPVleBd>E zCmVhnmXXcP4Vz0z%+0i9MUL+KN1Bt7l9}t)fdNLmRU(ut>zEg@ZU#he!Th&hDg`L$ zgnsP=c)W(rO+)T_{kfkM!tlEzVol9dtO{h0>pnzSyIm%+v# zl(mEX&$>V?!#=uBTIX9kT{&t|&=OfJoxy`Oki%R6wR;V>MJj~wXQBc6 zvJ*E(m?bO@HbE2onsoZX4b!V@9`AunyH8FKE5tFd+&+JrdwK4YcK!H}5|3jw7~*)*^;bf^9WDjK&E zCPcgx*O^!wR-rDJ`(YDiyAs!(uYpc5%8Z?L*`+dWM`;Q9JY1CTT8WkqjP4mu{pbL- zr76=ugYs`JD+FYVTx+($!XrpEQfDhDN=bnME8o8>#pE~H8UN5O8>@In-mt^<#lhRi zy)UQ-;3=nB4+{Ot6}v3PwFP!}hte-ESF1AAKIL{gg`=zx6pinMjtPOhy)Zf1V&o2z z3wk%qPi6Kowd2WOzez-e7TR~`yQvFQRK~|abDN#<;vstK`{_=ia}Jf&^!O}H*ihF& z4DS^Ar+nrb4wVaVcpK3Uv?A*mb%R@PN{2)Md6k(w+W`3?rAV{~1+yajJiCHc^&h=1j#&~Y z%hT*-+$5z55eIJ7V)b|=M@<+pnYmv#x!^+y-{W?Q4S~mh$<+X4u-a3m5{MN+Nr*!y zd8&k8XmJfE7^KzMgtb~N0V_+wv5ghdvJz$r59m0G3@QtMHnpwpE+pnw>sGNc+Dg6# zmJ=}3Zy=aK+q;|wEm!ZXhBQ6NaLyv{4InO?vhb!3l8sW)w$Y%PVqRgO1%#UmYR~!QAoSVa=X`wP_by zUA+_j?K7L4Kb7_SdNmaiLdfl!sgW8!wat{OIcPWKLlMkVLAeK;GGTK;Wz&!9Sr81p z(IJrq4`;yaqVC93Kr!UJD%%6p_N_J3QmUGte{jw8iuTejw)F#dp2_qRW7y3p<7U?N zmBPu5o}!af47d0Vm^cYmQem~hpb0v~Hu;MeDV4BbxzP`KvUODPNTS?>_rzW$GfkE@ zeXGcnGBPch%t%u&w}j_Z=fyryR#=g+ytoZ~;rt%N9{>+=@^A0JluaJDDwqA=Aa)Xh zUggOvL-=v=N9O#XqqM)6)-X->g9{Un{I+s%RW%e(Bk<~HG6A;|9Bi#Sa)kv14$~sE ze=5_esL-^D#M%3a6XsXxsTfRGIyH&qK~yLZFAdSH(<)8K6(y%bj4pS1HVN%XQDlI< zmo*BhGsxNs$n_mHHVZ=qCCCz6EDDr@^WXIV@c2X6H5~KVazYJdN|=x_P<`{cld1x1 zMd;R-bQ)OT!<5TXF^saOG$2|5r)fW@DALVCOu&Wku~^XwPY(T(wBoJ&kTqPfsrn?F zu%DMATLzM5n9T&+p;-7K8u#7Z*O~#ge|$vlIfB7cN)0g#sJ3?uBAiE`q&_yS9-J|( zV^Z0?P`-N9j-IJMHZz&A31QZ7T{zuC1&~!ogJLzi>Iplf<-XYJ9Ne{qXflb`&A0vx zGaQiGEGQd!ACcK9c8RRnG8Nw$+Lf_21=(HCACNa+TBD}FHCEeY)Oj4jC|><#m!j5w zEl>C>^#-xhCxpj&PKq*Z=RxJ;6R048qyXH5Jf{af10O*H;4oeqTV_J>`YRl#3`9o` z>atfXTQ2#nBwM7Z4_?ZO&IY+ci_d-5xbXMG*^mm3;0^YGHXU2hO^ulW3Nn6imVIcz zNK%ae5@n1*AR**i2N0VvS@L7E*r#UQH~ZX)Td8zyn(^5_E1>Cz^bI}^Gpq1)jVu+{~k8UB(o6nIoW+i;>r+XEnEG-Q9)){ zCgo~6kBWvqDu;zHX%=&L!@}QdnNoFbhl3H|hDLs2v0G;`c84>GCLS~UHLrWq0Z>>4 z%AgTy)Jg7H)(*p_t#@NTn|ck+T%#0{vlzPoi%a40I3wSFz@uNA!Ejsq`!4kX9@*YM zY0($r05T)@V}7pzOv=|`?^2};U~HSu)uv@(>Gf#oRYQ-r1%T5o<%*?Ai8|TZqH;)R zmW4D^QX`KO%9DJ{8>O6ENEq@y70Si3O5w5(Gq{OivesTw(+)~gZs=Hwn+t2$csFde zXEzykEUUfWJC^YrwYA2$H(a3w4m$sR?8Vi~@2JwOx|N5C$+)EC0x)r3b3@bk-rINM z3nJnCd4<^I%eHPgV@O2wePtotls1V^_fKmpuY00S$RuqI+NIOX1~wXlQ&}Nj#t2?T zNe&XcK#)tY=@N85C5z==9y634llMYKHe+J|=9H0b>c$^h?K~p%Md`Q{KmyVc96v^d zG;km|Uuax0c2=4*A2-v}4jTJ{Uaxx;e5(&#Z*#ft)eg z#jY2=wqwsG#jouJQ(VlCirUX;cPm%eB+=CyIHZ5v3Qc_~eY9y`TXdz+e%*-XVe%A( z;-*9XY4eJJ-rfFdbD|5jS1Hr&Uv~oYD_#hLXA!d4KMB7DO^R#JpEv^qinTS+9e~G% z-%Df87A@+SRE-&o4ks$k9nvnbK~`REAmOQo>@sC{AKUd8j$EwF4@;NDvqczCitqyX zWdlR^aWhQo^I0$@pvp8Q>(tC5vtOG{WDT;P{d-s$3_sw_jM@#mN;e!_+Ohf%M zmF95r6KZ+He7FcS`@;J_5FW^qWgeQ>YP2Sg{e&miLRBs7k?~%_7~LXHft^JOX4Yy` z04n9t&$+jCG|egMfTp-5(*cYu7W2s16kq-OVF)!6O2FqI!4!mHpg$Qu$HY2J%zKeQOBb?!Dh&mzPE@1Bke09^t14ebmtQ*X zP$UJWCpRQTkQO%jglEW*VN%3J1yZw@ex;fn*U2 z0)Ap-wjX-7q_|mN5m}&-+<0o@0{CP>Qhd^aL!CyRM#)lu2n#}bpf^7)^f%i64NhjF z`2^>DPvo7VBXhLmD_{05@Ek;pyBbv6B4k_Tvpb_`bE9d&7^ChvkhqHl_Pb~eAjBgp zdkv8rrVVa1mP3Rl=EQLH{y1O}8e96wz0QE~&YU(+svEp7Ly(ROa_>E+)T1ly0U2V9 zHXy(^n+|*A#OEKri*cP%hMPQFm(_q%;q=~AoS#ucIET+2DUZ&d&yv(NY+AW=lmthG zw+Z-*8@7rXUjGruKXP+IlBOQGW?v<2+@d^Qc7EZ-G8Swy()%uiBn&^w$z`#VZ-r5! zbrO9va<8|hJvr34+kW&Nvvk{lRBoZjKX%pK0^)#sgR(NNZP*afrT|1=*?vFkPNd`@ z6$4!TQo91zqGf(8a5aD;oeY`ceOBH{ukI7q?(aNwEGVz`%j^mg`=B`$dSe%BfhcL9 z!O!#pkoiXX^+p_ZQ9apF10RD;{50pt+U8$}-3s?eYzzQBr$3b2YO^D}i{7H=Hz?i5 zMrq_ifi|5+kIig|$zUiTf#wa2=3l2bYoNkSLSS-=sGv;ph}p$hHuP#E1IG44>!}_n zdoC{)BkI4ny42`}+wNPnqWe@M62df7;r4P%h5tE{eOpj1i_ge8xA|jTjHz-hu;_L4XaZYN^e{cBbfKU*Wu=S~1`66Jm*{2560uKyAtX!1MTy-UE*%xVPeWYaPcMg(LXR4EM%%RUsoMeJ* zk_u1jpJW$VUL-v@paDHK-zT>RrVt_{wjDt)PRiAx$T(3tSO$95IW21HMG2w zQAQoIOOwJXV}HZH&#LXK@GP5;LQy<6oJ$B)t&tfv^ru492>>Hl;R?!h#i60pSPXk8 zd>tOSeZUXbQ_3J?e-eX^>W9LeiT`HRvEI%1<>>bO-DJvz+FbGA}O~obo{Ip`M9@txO?C# zsWA!w@=g{lEiF}H5jy_}I!s&Ts{XEcV6*N_vG_bHF_L}hE4G`zfDeX zhG@;NSzqlnzM`@_XwP?BTlluebt<&{fVd6JQInxE@M~4%TI2NgJGd@Cg0!b36WtPd zqE;TEi)FtP=-Q~m8|1pt#d@$E`5L*S{1+G8Jq7M0#-Y zxrc-WjZ|iuNk~nab#$u^Vcdfl*Jn^Dl_2bm4A@l}w>U4_n8U}D)ajBcm{wi=?k-#X z_g>rD-(PnWJ`|+IwvgfET%rU)gNQ*jgvExcVwxj6O&M1sccqlhg9lj|SL1c~Fs|bONZMsHiWNn+0uMo9Oh8!aZi2nLt7*FmlO+0%%XPy=k8492T4>5K zYE4VyZR*u&;6iy8;DviH7yO^KTt?@IkF|k|!9}}K(ld&h8syX{$Kv2`Pw1o~h!u5* zQnbDnS5ba13H3v$f9sW2Gpent(iY>o%+mKRP}@9(tJUnD18trA%LENOEx@02%BPhK zm#b@Wd>QENvJtyj+!ZM!+&guA>yrC1hB3t%pyGqo9$5)!Z*(c&NYUVj)XBE zrxH$7pSMlAAw1f38r4-G;6)d@tu``G?jiJ7v?R$VNHDXp*(Fpik=0cTfAYPs$qkp z5$w0kfc4bsS5{f34TC`6>Jx;r-p7K%Xerob%2?9b%?be7@(uni({>yy&3M z092Cz)Q5}@SUdC~P`vbBdS2Qn+Df7oNb9`wsqcUnXn2}jau;MkF~$U8ekOJ#HHK}Jhg*Tb9IN;9PyEr=c5t04CCA<56clTKx-8y6wQeVXjxYxFe2JlhbUBBWL ztDCYfWNbPBywNK-o$4q^?)dwBq!hacVt2J~ZLg)EbJOlQW@op1nLqJ&V4Dfkn+U_l zztjZA8}x*p6!}>T3^k&{-m(zcUgh_{7N0~|!+iTrG@o3oV1Hqyw#Fu($j5B+emmoj zM_=gZxMx8QrpQEn_v?D&JfMx&r{a2$Sk+|W+^eS?In(mDrxWfWTOOG(Oh@bF$_iz9 z^$WD~s=x9G`TGfZdcoXRN+aMQlUpv(OwMl>NU$D%7ZHE+c85vG8deY*0o+Y9fA~}> zv-TBXf5K@_V|ZFWDdvYR=dux#zW4oO0gTgYgt`8QP4xJ=#>D%_oL=6+&eY0S!P?x= z%GAy9-@Ct_37gXEN~lBG`>b?y!00&@mbg%t%<%Jfvot2Jq*R6K%-|vlBI}uS*tTHM zb{R}-k6+d5x->R#M;gvRw$wbm*CB8?){&&k6g7+M4g9w45;k-L~@#&j&V3yWoxxakxa8}UMV3QN;%PouXxwH93~z8 zRC+clmiU+5Ps9&Ltfm zDob~4?vT5EdbLtUuX4s+q>{)n*~Q~R7;z+5FIOhVP~_G@B9Y@39_>T9+qeLML}s05 zGx2;6Jr){Ut8_+IOLrk5*Q&utR1^|*lijWw6z30=J5^|xw^{|e7Nl}FE#C#<(9-|J zh`4imz8@FiiwCYP7L8tc5;s;5Z&z^FY7_;1OEttiIw8A9un@jPfpy9Qn_Nm0S=pC7 zd3u41lPtKPkVNe+%@;r6n)F-h`s4LfW}v&ISwzu zK=Q)4GP^4HTfO9w5f3J*2L7{WvQ>p zhq5m?#JOv5nXHR&j80}WQX4@R$g!{&Vr%@OHgu9Bvtt~q!V=>u9uA~#0=f5x<;H3_ z@M9`=$|>pBPzwb>sVG%*lFOF zGbCPAEW&pQ2K#K)-f&CU9!O1gX4K~0D>F<>|DPk5=cCYOo?#R+_he9U%MD+ImO*AK zx}n9b-b>y+RJC-a87SAo;xC~8E`$)gWaT(E5GM?Ob_hm)2;=`@`)6uRBPuQEqHk#9 zU}|mkU)-Ey%(zsa3~bOhL9*DP*K^Vdba*WU3N@`o1Tmoi3hYzxS`Xb!8gjz2o#0*{ z$W3kpLm{tUA<3)p)IqlO(Zl=kJwy+blp~?6erY{s9i}Pkk_~=LhhkJ(BamKXxG&Gg zlxGu=o#x?6^!@3~)0-V@u2}84njL*i)}Fgc#PrY@N{OTA_~S)jsYd<1LwC)^a;jZs z5>Mf*XRP&HhKRAjlTntP5EXX5q~&&UzR&wKu8u&1rNW#3wC6F@AEmxH`)rX!kzk(A z+Iq$7R{QBX97Jy7?%Fpb=Ym|_Y@%^F9kTh9k!J9Oub_%@R$)IcW^Y^2q1d7mCrMcu z2~_bA7_q0E_%p;(kt0HAQt@gDLgv z{_}Oz;hpOAe_p2fr&LA$Z#@2a9XUhY|4*enFwRnXUgk&Ap&8~}30U7A0WJ}bd^2bP z1YSFb&}g>6Ky2@4*F{koopgPz@DkDsgS%(zMF^hhWoz0X;@HWM(Q$~l^LWGl>h*KF z^>TV!d-^wLuRapnf`Wmp^2~^yd|=4Cs)b=Lg-gy39{*A4KKm}Uf5{>{q})750~$Eh zaHDoKu;#kAxzjr$StIB8g|o!=?mH`K;ILGWz3<`cQ|Xn<8^$_k!zb3*>w%z(KW~kM z8gv@u{pC!9TlIu)fQ*chjCO|F6RiVhvPzxP%mEU(YX43a;zI@=nq_sVam@@pW*@UG;%v}7>?)~u7 z_5xUI{_FIs*skrrwNz(qd5zTmmov^A`I&0MYWdcg0Nx5B9oDo5rp57w28VBGE5>$! z6Z2`QfVDj4Tu%@xgySY#@R@sq$hm-ZNT=-^Wh?@x5P-V~2D%%t&BF<>1S+9Xz7Ira zIXr8EdZ(D9%u}My8E2g-F(ZTU z8|fkvx$wc%Bm@sy!(x>6;_k89Yb+txVsmH*IAocH0a5IWvbF#$@(b!Jk)`Rkg%Eme z=ZOQ65Oh?dCGh^A!L{uEy){AWp{W6<5~*kmmEZbBjvJzr4#{2xV2&JX+A@h~3y}ia zW^T-H(9e0<^rG7#pldk)8J3%6$3YQ4A<6!;Cyx0aVfkN0!v73TPesdr>5h3ZuM*Y- zBp3J~@nMjffl}qnkpqRtBrzk3shc5{U?my&CQ9~MFhhU+GWr0Ex zJ&E8R#@TtvNM{m_wWV);zSwl1y0^QM{Q7u*ZvMs9Zx689vKT=vF@94B$pCB=8++me z=$uAtjO*79oP9l-ZUJ}?oY!Kw!-Z^MD4PdDPbqj)0~QTAV9Vk+3`c1Wn)Fwh-(#2K z-ratIE?hl-Jj)!VnV2a6tGwmV(tM^4{UNXM*p@uy3R+uoRdBt%Fqh(Sdm^`ZBbn@w z3hEN#XQf?+%tGY~!M?v1urz@ov$)87yuQ1{eceg5e=yLl>Ojps-)Xe^afSXqNt_y8 z8$+p9!?v-{_5heLUWoLsa4xKwbCiho3Jry)QD)#9wSi_ z%C`}6JCPX;7^}48wmjMSLQ|^rHP_WDmK@zbM&XS&QH`j?rAA|Qld3fL!KO>^-ykbQq{hRHj)V(6AmW-q(4~pA&(?10P=cQ4^TSK1;-T4 z?Zjy_`$A5#tj>2Qu;9;_c&@mt2kv6mpH$7#W>WPDb$4+jYg79s1+t^@MtnFAtU(r) zP(37b_`l(M>YVemGcgyeOG&2_E$WGWiVx_Z4q;K|MIqAcd0cFXnDaB9UffI$3)%}m zz5)bUbsJ5mQ!a|ZtCdY}NrLjwMm0JJoC#&jO{U{_^bO`qKE%v+9TUZz%K#Y&r}`$RJ9vNS0q6UJXXg8bL9y^Z z)C@`3o^U5>6G?&7X8oAGsB0_@nFJ3_nT+9Xe#&KH-{tBPLn~LHg(aK?= z`*>1zcwGD78 z%oR61nLCFUT0x2lo+>5;D;9YrFO8o029wJ^7~@>!Dpq7>3-7ok-&R}3G}4fd!#a8_ z$zn$}L^QbiHH3OP7DW4CK#1r${39V5dOaZBg@9n3HuF(dWc_^y#%@IP@boSXo32>* z^gfAGTK=slxkQu%Om+fj{i8jRZReTsr|N$DASf>Hai z3(z*xv2EM7Z6{BRPRDjSPCB-2+w9o3ZQJ%{cHZ50W_D|T~jz<%_z&-lFZWkyEA9rB=U z`Vsyvz447}LbJK?Gn`TY`XSrrbfJB!A1qA63USUoiYT78{N)hb(~<47Vg5{Y!b=kG z`+lw7m$3RWAn@;1j82)JDf+vLO?(G}{NJjWx`X+*&hekKkC&S6cNN3*mao%~ms6I6 z&W#BuqO;&P1H``mXlw}hTcoTA5bC$!7z0;p!b!7=xj}HfDm<7B-(1Cl1EiWWWZp=W zUU9W;&?0inPG&_vxn(_ZU2&N{A8mF01bznk4Ms&f+FVKKGXN=WCo#Ce$ghMboT#w5 zH&M)-gi5Kg@Bh}WsaE4R)%&bNG>)N^S9WvwgTQ+P#DZDPxPl4vEEBx1rSNJ&x6!I> zQLV+K3D(jwch2m%k}JsfEXa77gOXWK!#IX|LM~I^Zlvb^U~;c@(>-TVE=`J_jcq|k zRU4e3Ek3Tpx`E3}+w$*yN8OCm$&ywO-EpC3;+%L(NNyV29)({mwMe^3`6|NG0$wup zJxTC%+92T(2eqniJZtQqU-`mN>^SpqX{`f{aRNJLQ9}@G&f!Py2C@1L2>nP{iZ0Gh zmht+l1j;LF+H42dLRd%g?Ig8#7PQlTHSSIquWG{1WBG%g0EBy@0FlN?RdQ1g( zi5$N$tpUq6-1V@1FT!1!Ayy}U0e^yS_=z@GAlb&{J<>bVR;&Ql32Po{orXAa;c=S9 z_LVE<=C64E7>qkp2hc|m`mlSjrJwIi5xcm31Dh5LtPgYx?F*}?yo+>eC?q6f4Zm>O z+^gtoTG%s5)0PU5~Dh1HO!nVCjJf$h;X>xMMeZOd4^vd$7tfs zMd-)XPZ-b#NhrQBO0+y}Sp?;7_MVlhd{NKoUks?Jdsd0kDQvt$9U*7nGcH`gXW;WY zc?QA@w*hS1K2$ohF?aG%=kMaU(4F^r_kcSDsN7eNp>I!>8RWgV!RCw18+-^Kd~$bx zXxt$BK7fFJ1>9#G0uL*C1Q83`W(H7#BZ(x5GeP)6WniqU*eBa2?*iZRO})&%g%A)o zWZ`o9yi3;w)upUI*ruc5Cno7MKH$p z6(oxU{=&ti`}{%mA%hXyn1v@sTX@WKIv3)Ot<+A&%DJ;fzr$}#G4rH#NHv=}JGR9b z=M^SO{uc5?a=#&Qj|hFCd$0PaUN@8|lWK)g+nBXr4;#WR@+Y1&i(&@Ym`~)dE47$J zzsv#lW-cbVJD4;zp}W{A*Z_I};`ngfaKnD$Ty0edXlqEe9e*e!*EyFuFBce~`JB6J z_m+jt*##wCBQKIChR!4bIs~lMJ}q3*TxlgwxfAP=y#}4Q8uF^X7y(Jv{A6vq|mN09TZ{s&5#7}vbvBx^eA1x}aI$?t5 ziMyG8M6pGr={cmR(!>bO6>HA5&Lhs{@9j`0ao%*K-2Mrg6^z4TN0kGN zHO3s3>K9KENo|(6Y{M)K2PxwD2F>hEAjRhk7wBDVSx%@~!$QCu_l=c7*)~$45quagyAd`lG*+u5-iQ?*4nc%xpV{KA@l<1a zBim)NR@PWgwJvkSM$9foe1=8hWYB_&T{vNRq;t9atQ9AneCc_E?%ZkvS6B1aI5I<_ z0T2}02QQU|)zy2y*ZH3$K zS{yC&0u#4^)}7gY5-i=~8(Ot}EO&S$cSfRhAylSLBmL5QB+Xfp2KQZg4u7KqDdxDH zbA*~|VyBQv{v8!Y+2T`(ZFX@Y>;8xr#G<)K{B4x9cfIi)_&?at1kpfBID=0K*M+uJ8RfZFK+v!J z2ACpKEeq#_PV`tY`P2Nw4c{Z?9khJeuAjPT?xM;i3GY0v@Lxp#jR8YwGkEPTS;juf~;iO z(ciL%TL28W=U|qZ=EWVHb217YPs^!M!JFoDQ)?Sm=ye(%Cq{>FdmT?+S9fk#UR~+g zU!RvA#N2Z3-^t^`KD`aYeabMIc{sf5Mgw)CO~9lxz%n*XiX3#c3wZeaM;CYm8;O$e zia0#x`Dg^jZj(1T&&T*v<;ay%1=3D>IfwR*Ij82n?X|gJzWotN08oo`HJDK=V=pnP zi7^^CN#QvywMm9yvc#t(#rdWAIzf=Rg9f^kHHV(XHX= zAdA?_UYtDNOU<3XSRg(tN2M-!76xIS2`w~BNj4qoK7JPHP^d94-5S@XwV%*4 zG%v13bxSO1{up1N5;ORmWBS6LciG1zDdtY8C=o%B>dRd~q$bECqrOAL)vc{FL1ODI z0cx?8jVLZ7}c!_J+9k0?Evv)8hmJ~|`EKz95!9Qx1GAxuI9aRS*7C(!a7 zb5RL%pl@}NQH&&NGX)_Rd}?ssa=uaxx>?AsT8SHtilt{dZ#rqHg4Df@5Fs{EI-GGE ziH@a6vlB4l>@HehJOkz$N|?b6>2&#N_O6;7x^zmf zwS~8`7o81Pji^xiF`|K!!Gajkel-Txxx}}EI#am$$v2@EK81*`q8+;k3CJQ(iCgLl z70r@p+IW2dn6yO-O^bh||;Fx+b?N**#6T0qKn&F!023 zCT{hN*-Ay{qfO{&gz3V=;qW;~IA)-zlO#C-^wl7h+Hk9CSZk+# zU@Hn)cyT~nR%pQlN#X3bwoKvczc!&z-mFG@H?b5nm;F6qD6-W4T$T4-36&%24xZ3J zGDW^m0S(h`rdfgqHlHjMAvRLF{<>lE@>@X=kR3cDL}?tU`5;?PS4+-iySsXUsRUx@ zLrZd5DfPSLz#MgIX6KlaW2nT|gtpsLU9KH-2UCXvMJ3c_!l{MuDY65G}k zF2LD#9P6Pmzmr~V-$iGDdh~E3v;Ha7COH&I%;hRIZaJ+~nEEwnc{kC1*&7_O0PSk* zOA#yytyukW)qcIz?THP5cN*)E3{4&{Gn#f>H|dijOZH#VEMdIrtJB+cgoyRJL?oJr%)VRJ;$N3*qn*;;gO)?I8- z5#FgFxAU=&sI{sf5*f6JPiFrYC@j@QtowMX9yv?67?!9m~cfBIufIsMlf`41ERZ?Do%dE`1N4We5TC4)eiFO z`0bDZXzSv!Lt*qd-PSgHgRi7XPOsZS1Y>chqRiN2ey3LsuFR}-S|aQWDukzXkH>Y# z&MTgypg*49%>;vx=){;}@|T^kB;jH$ZDh%7x2_buZDe3CkiE>*;eLJxkShDA z6{3s*Isut_RL$i%CEHnk)lfnm<~&JqImAMxmQinl%>gB57cd)W3w5d!+H&!_LQN)| zb4!pnarxSR&5YBkl&02etuM?+?AF2HN3e=^=#k0eu0o|MQGngbsUiEw`cM;13}u!P z8Y{Uy#HEv}7M9r7Voay7VvM0a^Tr4l^30)mrWo;hCi_oRi@1_z`ZwjDoW3{@=1-O! z5Rx&_kGNeD(+*Wc!_D8~OW}G`+0^HrMpr+XsOvxMX;Y~$EEF1Kby-}P%eC7ou(rtk z87WWmh-8~`TCnw<>ILL`h61kBY7H%H<_-%$Mo>k5VOh`AWQ90eFOE@Y1&r}Mg`220 zsHIb zR~b~YJ*+xNwog-7`(H=hfsj)?yr(az^EqfxHHoP7r?WX7N#2vr>y4 z&H;H=+=E4Z`X~roj|@2z^EpCFclj|~@B|2CdjD|u?Ir?;e=aA$aKkfzX$@vfWE3@) zty4JQ^-M?7G2r<~I%3xDMbmk(uy!DOv5ts`-~mf8RRo?wy8asc6l{}L9Gw2hIydxM z8EQWtfzOUzd;b|DoCY&2{KuX;D6H^aCcvmxrv!Qk=tT6x{m zxDq$g^9^Fpij#rAamrT*%o+3-v0tZ<&!VP}1ZKXiy)V9D8hcEU9RB2$U3{l)U)HJ0 z)30EA6qa>h17M5;SLRU^Y8gHimFG>nSq@Bf#$Z?v&*nj;C8jH>=cc79;QXgAVtoXr z^Bt0CN~tFqQG$`rm(-!Q3D56@O4$b=$Ee${K-x)n+#|+eTsF#vK>b-J>9v#sJe@*p zlaX$?G7_0KjU2xH(wReSLtYrj9Td;iL%^}6T5hmDEx_;k5?>vc=WRP^DN|*K)}CR zPyVBBs6`D&R(-E)Sl`$a$$!qP|GRGdqj>yF?O6K<1of3^)OT2?LyBCGd$36k;~U0q z(E=&gBMzeC_p5ZWnN)k3{oI5d2bP8Zc{|+2OR-qXv^`&*;9S;R0&lFX`jZE5=*lXI zETLhq?~?0&@&@WH|kGBdm>1I zubHrh5Db4veRj#LWKpAM?xDWJ77w9*F(ig?4I{G}_6FrI^PoprD$^7T;{q%5z*zG+ zmA@=nBiQ*d_Hs)VQbA_tL`)~o%>FUVx6~qz;&Tfxw})vK^i-B$bqyvF8Oj=JvXNiT z5x_^rh;H7i%vc2tRplmSISJC#T&<^o2c8?1B!#&j5hY5KgXwwT}iB%5DptbDinW#gj46TUKL%XTv zqe;xliuVt(fsN%BQB85?{e|fBa;i;}G)cXPot~`n{fslljlXqkN6D4m48AV_W-?_1 z)95^Dy%5_wY_Rjs=XL0#i@k}C;+j**Ce&PwX68YYG_??bV$te}dBprcfA>Vstj)&| za{L9^&0*@Si^@keHncIu3m{-PlgPSMfGOMNBss^Q6jP>>Wo;kmJCr7hbx;)ga#|LSy6Wddi07a$x5p=S8IXJ%O88E%ccDVZ`yT=#o_OddLtR=5^b zoaV$77rE0M1tn}N$uBxO&*}R>loRtI6r+or4Q$@)*;QhMOTQ6+mz`K1mz@qVc7~{# zHZM2}VV2rBQbyM6kaL}{MbMw@mz z;FXqrw>zZ3d&n)fG34hpkcS%xTJ*Rj=2%|aix`X5j?6f&y zzHbh1np9ri7h}#FG>yf2#EG`w#O|5a|() zSLLT~2ok&@f1K06)>i8heW1RvPA;1=?qv0V#@!=KS`i^FEgijPkr5>C2RCuiT-Q?I>f!9q-_&(O9|DlQ?(2E$MCU&w{Vvx>GD42(EGwq$CS&6$2fV3h`hr8 zc;wSsK{);;unYPIW&a3svYIRO5y5ha<-tH)lJlVRyD0ciMkiS zNvdM!yq8k5B*kl64dB$*b4K6;aLQYzEHb%%{>OTbI6ee`{a(*!VgFAfm;WA<0KX0X zHBKb)8*@id$Mk+A)gOWI^Q0CM6NCB@YF3%!L#bCJtjLd6QAY|>5kxD;4(t3X!99mn ztiI{0WGZU9iq&zV>M>XTIK`RCZ(6Sj97&=4)$r^My>Pk-E63x0E%{aO6;Wtb^Ee24B`i9p#|`ma(mvcK2T$G@$MQ>)b3B8 zUI}V^h>}`r0ai3i>Nsj;=(4yMtI2U{#a-z6hNOCv-!ej(oo$sAbbM^qMdA~lLBwBC zNtcYwR9?wV6>=m?GsVJ3g)Q%^39{7;vAceCEYw0MaMPHqr=Cc?~7?!nM;ea3G)i6Qgj_9#&9ne zkR8n8V8sH~E&0**tOV^}R&8b?8}klOUdhY6u~o)kY>r7up4^qz7+yx_eS?xq^C;F5 z;f0Ok;#MXXP^I~r1B!_AbFWERwS%lOfax0Ls^VSdkxUkL=Cs7A*%F3XHi5}AA?~j9 z1s7Nr1>A+T%SDEcL73EEI3%k88LN^WL4IUsqJj_-r*y12ZJv0 zuYZkGuv#DXjef9-jgll5p{8F#|Kf8VS4E;%p2{!O(482O<9l)H9gj-WHW}66h)cWA zBUH1=Bdo0_ML}u0uP{kn5yHkTI_Sq9E)_?Lx6nL#G#ysXX0D0O-va zqu>~VS#f%S-a)1ht_iI1TlA8wKgTqbaamY~CEG8adkso5q0)2@%@tC-ILFwh3_waD zlKqu#A^=!F-|rJ;p-D{r&U}ntT;4tbIo*+LKO@mJ>`kM_rkRWiht{HYA+J`mZ2=6W zvvivFmXAODE~ei@^QdG&u2!r`WKE~Bpm(7EYqw9$2~S|k6b^D*J)x;E+*l=_6x~sm zL%Gah8!ti_cVLt#_ zRrL&{Nr3c}t1PE4zf(NdW9&= zdVx^(#HUi6_SdFV81aDZbPcJ;ih4_}9wDph_y|p!^{)mIt0G}+_k(Rj5XAwuqHS*M zenk0D{iHj%`w%1@lziDfIoNRR6hy;ILQHYCY#it9cwVCeD<+vx^T(m9A&r#TU%5iEDV6w+_&BxH)XZ;2_?eHc}LKWkMO zR#S?B{C(W2w@c2$9y*H#rr8AA4#`3T3JND20yEAD&_Gut*kC-v%Th$A$@f z`owrAptR&fJjYxyq?~Nc$5CF>N#N4~;;3-44AiI80<>O_?kr7{Dc%Mmakr_d71}n@ zn*668_+}sQ(QbTR8b4K{aS)BO{Vx)EHyh4}O=-r3H=nF41z&ZWK7!bakReWLHLP~E zS?EgRhdC`}0es3^mzwQQ_T9%%KID4s7XWwGPY&-$EytHa-6Z;u9$>QPIAKKQ$Rc`UDtf&{g1-d5j zOtvdd5YZ^HY%)bITH8hz2&f)4jx9RwQ7Q_nV9H*F!0(^XwV{XPz9&dRF32`Ez8&3A)Z1f%*4)i_&o0oOL(Ej zVm2~I<#gw&&kU1(YGJ2qHk<5s+&Iz65L&!$2ROAx3Hn>39XgfE9_cfSP8K@c%gS)K z_b+lQx3snz_CF0Mn@gK%FrZRG|IS6aZLUr(NijsdI13_OuN#0WE=Nfsn@+rC7=x5u zO%iL8Yh%swj?o!*j5x!0{8-=_hA(|RtFBhhtbe?;UVo64xT~)dze;;_glD~n{RoL*)aiOL5)5$5M7!FFvD&xjY4teC>Sj2E?((dF- zERV%MBAu^mVxYj4E@x`7+E*{pSFR)1rfzrq%hIDdZIxWQGNs6av2N~CS`=i$H$+Pp z+d0|Z%5Dz$N)I>rc?2|?M!XQJ*>=7k=}0co#$^_&v?yBJ@vC{$ZS8>-b|)lApVo|X ze4c5&l4w9CEg6=Ywb~IYDT>n&US^q z8N%S%4un5%C;u5U(OPVSEG^Sy2C_kM`V1J^jF~oHa_`xDBcJjwpGtMh+SvkI(+K~7 zi%~QbdW5_tJ%s9qZdn;AHrc1=ndE|+lsmm|^d5>6K>U2(2NQqWo7C^8f|%DpN`s6F zhq|n7D&^9gOco7=Qpfi>A|AJGYFei%Ben4CF)UZq)B5P1*R2tK$P{Wb!MZv@9W1LN zsF?o6jjK8tI%x;~HEyrb`Kfi7A&h(XcU)YRDpRTUBCQj{7;NX>>qvBV6cS7{YsinK90LFQ)uFn(QM7>E=52yrZNApfqEw}?cp+ihlI20~mP zsA%E}vLh>D1QIK&C$WDDo|hVBCQ(r1t6^e>cLT@DE5gx>ng4*e>+{TwJ-{(d+ZpP7 zLw6r$yI1lI-#G8cDbGxSWDLXUn+z0Zuumk#v{+N{Q(8q-nIbf77e9|DaUNKseY)Q2w+5FjsUfvZ`U*)P=YS5hO&OV}X=7NU9TMEE;R-s`-Y z6tB8Bpw|X5n@?_W=%?@M_~}42)TsjGsREg(faC~}fwGVhXIem-ik;`2X@~?ML5)2# zpJL2PJCY9%Q>Mn?hDEf0s*p%eGoRUM3Ld^3gSRSCqDc}$!XSXJRptbKjzPF*OVlx_ z$(zaeaD;kEvqD*ILnmPuWB-U@WJ*s-+B>pumje^MD^c;CF&dOV8q^$1$-FdSN-`z_ zDG^ox{z&rEmk=x);3H8E$N{q5?RJ9ubs4;~)`s{Mh4__)_~ncE6^r;4iulz6ZT}nP zIVAr6k2l8dh2PT@bqJRuSGyLGw<4OHU+zE<`;4-bZiFGxr?M(RXtx7!bx%TB^yo^* zHvq+`LNDpTGP>!a>Thf;9o*&T4_y3~CCvKnBDrQH4r zF87W{w@YA#_9a^Ui~$#YWUup%Q``@uDwhJsI}E-uDXk~05;An7#U)Ms(-@?>Znhke z{x#Mu3ziCjAvQ@vK+FpYGj{56(hIxGsr z75wTE3!nD!^1@0kCUGt&wn(IEswK?3P5H_BUpx~%g?6_xm@TVVah4?=bp-~D;p7=N zh>;gr@ucZCukL(#K`ZResbJbtwE8A=`g>o!BmDcZmvhX9)#uwy3X1CAIP3pB_Wm#M?7!N+ zCXA=bLh9G#cxKBTaeyzB6gklkkN_!QKTNplFrsBMzXef7pHWh*;b9~4Nm){-wzUiT z4d=I2o2CshJL~X<73#mMiG+2+Z5Ahw#%mk=o+@h_f7^a*S6VLw`mKDqT&A*c+}T~& z{*jvGd&;=-yjp5`S;dLYBG01{t&G-jS}kA^YUjTsf#B1hjsJO?Q~k`C@i0emT>k#b z!0S07p;v5sJ;?F0-X!ZjDuL$txh8~suS=jhi_-p4&HIjnu(h}I#{2FQOu*b*?B+VC z5PYnOpS2fREcc2eko`3GZFG0NiDY?&MgHg)>}@rx;Mou$e|LR_|BB%KnGl@qc6{{y zt`Pq@CNXw`LEdqkFLTo6A9HL!ctaEa^LECQomUbZf&R5hste8NF%sdipG8y1 z_tJ@q5AE#F04oiuNRkEV*CosT_1 zmu7gle+vtRv=z)v9MG3pdP9oXwlolba}I9B;li*MCShuUsaWr^JF=W~Gt;BdD!`r6 zEnP#whAL2og&uh>iF-bNH3C~WTN{eDx8iCrFzCeHnvDfIvl79FFXtpalqYg? z?k%Lsa&t~Fwo^tEX{7sSX%()UwVVM5Z*>g^53oIHV$xK!f~=Z#B1?uG!5e zKQC>=(x{AcriIF8tLLe}oQ9|1uPkDY4V^^wQg`xf_NPpNdRdk%h>qu(X$}5RAq2l_{2CNI1dO;MF2|5 z&Ay%0?(2rJynjxJKgP4>Umgf^6TmFCr-`Q2l0&g!>J4anX-iAL_X!IyG_&*lli_M} z)gL*g;UJSuT@&Bu+2zpRQT;)W&<;{WpsI%$9L2LZ!NIA0m&RmV{oLbVbeEyN3Z_9r zg%cZO&2**gXnNBER;_Gln5GB`kR1~nuGITVheG`+_zb<6s$}Nfrm|=2YNZ`B^O?A5 zRFJJWWnD^iu5o+$9VtIbEh&-0iDx$mYnftQQKlf2I3}$_FWv-nF>)HYKBafeY3t2- zt{PLCG^pWlcYMld`lLkj^{bQ2-u-9JrzPbf8jbhYCx<*mN@r>_%t6sXRY)H-vFJN_ z@Nw8rT*y19OFDVILPxU0X-525*j(GBs)gcfc?R>LK+{PY&J zf(&650lPZ%`R=L`x&2}DbQ_TuQnS*!Fx}xjA?^$%A@Y~_GoqmtJ(8v?MJzOAN6p>n{M|0A_ zazLpSd3sdT!(bgr>CU(nN9Nu13(!XvJ!4+D57j=iAkMLMdkdAIhZ(7$`ph7Zt{je> zJBi?24LjV7-8W%`zF_kGBwcZFa8UWg%If)*i5*g-=Efm3QeRVPuzu;P6MJIFPF%z- z0LZczDTfrWCFlZrY?2jubB&MBFZ>5BXU$CA=Q95dq*tm5Jb*}NdQEl%{P@SKr_W_! zW=IrXQw|3e3hs{`baL4BaXMK;eiGU}I0c`mSyP|f##p@$ySTUsDU?=*Z!JFJP2mrf z{6RtQXh_gwP(EdJjYbbx-Z2ttUW309DtRS|0YS;hqh@Abx5!V?1%Nk|FE!l3khj?% zfo5I+@N~7;eq1C_sssPXmPuo|e4kN?d=JCS(tSnNHo7daC>fKw86$RpO4e`p^qGhf z)hNdF_{WPWqn64W@znI(dCb>X$x!?v(U!)%-%(BijLWOTk!kx4)C8|ASj@2*P5tCK zMkG`OEO!o_)ge)l195#iTioGD2X}Vbr8Z}ky+^3GOzIZW&n$MhZ=c^Qquq^~7Eg(95KQGq))63I zuG4}}kFCSsM)CIG$^Cvaa``O2>}u$ooNn`DIyYWGM-&{NJiGRc^Mw@UjM2SM!i=cv zf!Xk<%txjC&z+t($d|i84IrUVdS9)y66B=HBC=l|RBU_2nZ$7?;xT2#*sIXCztF1{ z&((o#w0+&GYEp;fc7Yr71rArsF#r6BsDI%=W9;PDaY<0Sb&|>S=uc#HZp0x1iEHk= z5GOU#P;N+!B?kTsT@4X%Q<;T^o+)I!ksfXgOPVpBmo7hXcz5y>NHSw{Eg689*#}i2 zffIyhUm>?nlWWi&Rf951n$?eYn1iKoY8R^PEx_BwwW36%mZ%;?b_zh=6?wP|Ty zJoK(2esVN_Y74YcJ$^-N)r`1AOdTY}nl#jcLSHSnGBZWX%``S#7lZ#&jX=_k%Ck#% zxDJyXLj{9R{x)23JbLab%-*HnJCidd=*n(QGQT1HvM2q@P@J?_$kW$fMTAQK;}lCH(o z+D$Q7FmQhOJLsCvt{@hJ*1g=Q} z<}|kh+r_(D;)={^6K_CIxwx7&VR(9naqQk4Ix}zd2iKp3L%SZBtPxW(nPDCuM!2zv zHB2Z=@!kaL;T-++!Aw#M`(LtiTgAs5l4(zIp?+`Zt|>s5AHxrSREmbtZ+|h=5n`s0 zc=+-pjCv%F%CXzJs&1Ag4Q^SJ7+4USAjRqgHr{6pYKg};OT}JG^a5CugWcSi)u04` zOg*Y26ZGP5F=D@;(O!J?(r6$W(@!@yW$l7rm0s3vX=*}WKxW>E%lrXP2xld|nsOdl zc@y@*y6d8}!mXC!aE?6~#b207OgL^VwXYNTiDU>3y1FlXbK zR6lT-cq>r6Y6?L1h8#FQPiQGpmHu0J!AcKGD?^#=vdw)_6?2B~f!u2{45nX+1M<_+ zFW3kl8fzd=8*brA=ni7~4FTy*p-*ipC)XW4Irqp6?gP?pN@N|QfSO&S-CXs29?POw z1zP(7Pnk-7`!rUX$){4JHEXOWD^rV)r_deu)L_Tcf3e10)L(5{&#xPzVWEjCo0Wua zlB$fp-Qc}JmW;mLF)fY%%1hDo6G8uRN4Y-&x!?Qdi~Mjqx(c0X2(EkdFeOP{*tBiO z%7trfgQyR>S&Yt_$Z$cb%wBP$xFnBmpL-j*ecq*85R%`r$14uICP;2fx0(3lh29wp z=Gbm{!6rx+hQ%%w(g;Q4XHqQvj&2{bT%aA)1NOzG)N1|U9mI?V9QJ06`kWv(&$br; zn=Oll=!vN$A6Uo{v5YfB+D*~pEVE=*w9Aj6BS6p{OR<{p;{*IVGi3Mn4SKR2dddS% zJ#)#Pi8FX@*iEH(Yj536EWj9OVz7|TOrNAo@fn!da9{QIStKClQJBUV?zGec(V_j{gu zN?f?{uc04De_KWyoDdpBYIhG1AT;)7MI25*~piT`5kuO>hkD?&v%bR`o%f zX5Sk1!R+7WZ z3u52JcC3e-b5@dQ3USZm=TU^b3QB`*7KBUd5_+*V)1k4_`Hf8k>5brpEX*;j_KIrq zVzb)IL^Q!!HE-VYM~iG0Y@dw}qqMhx(u!c1*gj%%H&$UxRfY$p#h#4{xrzlKDZsMVjO{B&TJ)KZ*3p8CK`uy^Ki&ixqd5#e0 z4Q1Ma6o6cpawJR(jd(WL7h6LT`3Zqa+hAG4HU+C^bkJ8uST5XttDs{}G>p|V*<3R= z4zr=4kW9hiJ~dhecLl|tp*DodxhCsaCukc=EOF!i7MUr9%F7F+EsHrYcp zk3ih^Fb^i?bngr0K3pIHbZw7>|F`OJEWIqkdPvyAj)5C0*<-qh{O{k*qdoMARbZDb&B;-xv zRRhl|Y=x6E^A z<>kFGx*Ez_T3r2QReGazNSO!y^JkLk2->og-7~@OeJet%Lf8C*hvbiMqTb{{pHavj zDr$3JC`y9{uP~B5vajpt;1l);-N=glz!Ub109x=X`zb8=(XM{2XB>Xw6rg#&h8k8Y zvV5X2q_UA&OULyJ2pD3K+YB#j>_#X0$S@8v)XjiD&JK=VNJoAB-Zu5Vyv{I86NLN&{O zWajZ@2FN0VkJmxB@;j^N%laW|Y#}RQ=ug;yCP-XdHW8f!<_4wCj|Uih#S=70k1Chn zw+W2i-jj+B_hFBz6kbhqcunzny?$qCom_YTHPyrpLanR!`NP(^rVL`e^M|-4sGQFb zdUyL_qc2&|S z#Qbdhi_2o>s=O_nZC)7K7`Vd4<~G&fm;{J_>!*Vu^|v0IlC#u6AFkqQvzd6EV&Fl{>Qu(iR673N5A!t#=vGKuskf6b4 zr9Be`brMN3c3b-FcZwjWIJM0}1BWaFtr-}K1r)G43CGAp%*L^O$=6x1-Rj>Hh7m7% z{_nYytR3Z((|kXDb+xEoRcCXZh+7{#f;SNj(`X@#;)%9Nh`!W)O|Jab0bmELe4E>6 zM3Z*EU)4s@$BIGlM7Ea6+}c)J0jYW{M2bHviOotBrdbY!+GhI5Ls)qitN9z}r|P$h zd)PS=TCob=lTlCUYLzXQwt`X3#dq5CHWfxY>Bn~M83cCL31_4uw>VSL9&gd_3In;m z)+nU+l0D|CW6a>({G4{E1KojwC@NX#h(9}Rm(P*z8xO#m+Ep}hMzuA1iN6o7DaE&} z=?ehhmw#;WKqE@J+wmT2N9)D8w!YG$9(oR->O~r?B_WvhF_I4=r&`+tb;tp6|wTnfQ}t|t6RB!uGO?~4f^ z<2hn({}&jClvCayCH)R1tXcAnh9uuglJc_?G$6}@Dki^r&U*x^af=Q*yn#AdzkVOb z40viSGfv-xT-27>NDH#1DnxN87}ot)5$I2+U!Uku^;8B~wZa0OCpMi+#J8EpLmYDx zPp=%e2OB37E;Z>_ks+SNullDODI6pQ=u8{Eo}!1;$?n0qe|{Q1i$LsVl7y7f_p9L8 z2YIZiJlL)-t0T%t$Xl0rSpe3%&MEAJ6<12$C_MR>z zvUL~|M^2dE0)`P2H#R2Ei~-qG|NfIIjww3_eyizJzvG4ezkX8Ye?rcY@!vW-p>H>i zIhZwin)xs>rFOLwFv?vpwEaRs($burxZ}0Ic>2T6#VZ?eubH0Hpu*FlTOW#pEOQ5o z2D8DJ8Chdj>n5M?A2%@FxajeWOy&lN0I32dz7XVFX$}@h7=?M$#clu!lq{C3$##n` z2COV&gv#T&SKB;v06+__*%V?n-Bi*h1aApm3*Qv8t=~AexrMh&G76-p>bjl<{18)F z+eTz@z*Juy?wa11(B@w0YnB;Ghv6+Rt%os{~X%w7> zOOH#g>F&{ox7mak{w4kf)mO$ckS@P$ zhLhCyXoL?GGHJZD2BryOXtu%2}qSSwE?sMw&k!b z-nsKBoROm$5gl)S(Vq|!FpjLGzv=1QV?;36SkWK$kK;&$tD^?RZW;N8A(cxLuqj8F zUX2;0lW<5EM$mH|D-?M_X>f^@DRF)92;Czv`-pb8Mz9CuUei|Z_~M>@nB-<+n*-N; zl2pKh?BnRTr>tbH>BgIdi|bMoD7+(n1XUMffj1b7%<+J-kVZV2rL=;o^pMH=?`UH< z)-#xxsv$@|A+FSHlFd?P_bZU{;}gBKg|~Y}WgHV_o9z<4A>p4n0&{hQv))pg$sv(A z6+Ik=HH)*Qx|cowhd^|F&~}0Ln||kr0t7_=|Iv5;`9W7|oc%+z@MVpBtCJW;3`sX{ zAm=CD*!WktG^|#fWZ6$;evw|^cc3P`4F~4&!&{*95#jhgoM1IoEr@x}`-))UgsUyx zxIUW6$!XBT_LA%AiKp7*68`J`?MM$ues_qrRo|orDHt|qNl3tcMZeGebu z%1G*L19fwZIQR+h?870jKN0Qvz=V)}eNBaseRIu~|0lLLS<`8kX7hzR&{p|bP4G?i zw`Mxv5Y7BAxjJeeDq)hU>f(?^oc?f-kLbjzbv3P&OJQzn>3ooet%jh9vZf+gebpE+ zx7TiLPwDJ6B^8+jsw$HNnA83TWT3e)!QA2Tb5&U0=-$JDre?N*4Cr~4nQAFJ-AR)1 zq)D%i%5Z_fK#4_byMYoy|J92B@J9nZjzEXu3qa0J?GCl5~&w? z-LhDF54^&(0(w}vaeAa+eGzZhKWTL zTdBhP(lc1PjGQMJ&-QzYG7eAUswQjNn309<$X1g7`s3f9jLhS+aL9ZY0(Kt+y-s}| z4P-+avn^J2S4VXgS9)S4-IIJC6tVqE92lv5VqcHu+$o^73M7g3p!vpsIg$*rnvv(G zt4+VwqL7+ae+sW;BS;Q=kd=s+-_UMQrFroE66I+Y(qR@FoTg5?T6_IyHUVhT`~-D) zRn(GBCn98_H~;`{U~DNs=*BFo5KNoQ+9JNFsssiX-1cC#ts=LX>db01jAETH*H2sn zG?f8ejH8%EtRCX3nK`l=MN0CsvySqC@y1N_c?vhfF z?vySmDFFdV=`QK+E@>$V@w>e8f#Cmr>+yi+xWAp9nVp@z_wKG+OZdkKgmc1H4VHuw z>u5u$!by7bS>?j6C@YeP-B}5ucg5`Bm4sgipXQAo=f8ZuxI4US>La4|mY<6jYYnWI zUg4W`>l;}it}x(`i>2ZKV;jj%TTElY zzi)=?;$ zY7IS_Stv@dp`UA3_FurDdI-B6IJJVa!G|xBWg#};BQ(gA`WOmDNrPN)ZEMlGp@l8v zw$Q4(YQbJaI5O5hbx)+_M0?-jhU@h%&afMX_|c5hcPUOt2(2=|w`bWn?PygeDd_cI zzD4POPK7CJ+kX$|(9m(2Z0-)*zbN?Tj00j0cJi>y36aiOzU{G?H6h2xu#tK0u;;;< z^JBIgL$DAZo@eQ_apj5ETSKc{&+UYDJ_QQ~^U|Cu<(;3cL4|8QU z$dnUa;fsJY2lKlyN_rfqkrrOTFPAZK_EgIj#4kx9J#41;_1VYuj9{NJGm(6PmrI~n zL}6n>6Kx0yhTT(3JbPJ+?(w>yVJtWmDjHfd%|L;bR;>yJ;`E7@%X?o7LNyxYPT*a3MV>nFqh z067JR?!df^4P(@8%DZlzKe*2S`A3`29bWOPs0=x?bK4)LW}EWss&?|<8MDo-z!D75 z(3P7o)-6d(TYrSrN)lSeDDRu7BoUr~AWYCqNB%b+U?;Bo?!uxBOghf-ejU3Ym9T*MSKs<*BI zor1j>^0pW26PQ^6Oa+PhtW|>Lfkz3;g|d0V&Iyr@hToSt^ozj&Jq3+V438l+T7p>S zJ*|4dUtR4RD<{{#ggI|tZE$YtDmuQs%jFWk-zW<>TuuX6^WfY+@BBH<#K=#JKa@k( z63HQz>alv!aFGTkb_}2OjS#HK04`x**@WyVV_&Og##Mf*mltTLEWofiIscsx`_b`9D7%BE57(o0R7^;^B+}V)Nt)67kI>beURWw$q|=F7Q|;AuDP%KEzRu zL{=eNP9K5B@s8SkXKz)@o~3=x{4}dvF;M)=v9NE9TS%7#nT^J!VrO+iJg9K{AFAUaEwuNFkHtFz4A+sXm2-12{Ce$I)MC*WAxr47#n34kBq*k>NyI#wJ?UrQ zH#22iX>+P0U=vfwlV3MK{(U{Gkd=d-%U=domQcV}LVp&wnTqS@w-^eFh(tgSP3N79 z0BJ_w`IKRy6zN_x^b+iJ;9L-`hm_zOu4ulUH^;IGbN zxO831A4eVbll^@Bs2+NjRg=m-bDULWaAoo@{v^6{>?}( zl`!dEDk2v}Z1opemnOT?qx5i%*aVy|^y=gUB$LE$lAVI;sU#=)ggFMHN@h#y%1^3u zmK;-@t+Gcv)I`*S`1tK$UIG+UtI$v(t?h7R8iMu?M`4eig-<|H6Ent?eonXybzypH z{MlG?^6^ts14Lm~lKy&m+gN#Ou};mQm&)H%A0A(nnD;#WwmVU!()vu1;^Sl5#J;R# z0n38S3E~k||LGs_wvVkJ$&>iQccUm;mb5qpe}Yn5!@5d|NKuKI>X)Q`EBkc}V0t)N zyqzV+DHh%8ToYt65@;&^q!6%V$>bSW+(7~&*=VWdhm%^F=_tJNh$X(Q|KNvA3Go(Z{PmQOjz%&BFP z`l9M0f*;w^_@Ft~`ow`{h%g4Lz>T$62`yM@ch!G=#o>GKwZPG|eH)o9i-S-UJe=@Fuh6?+Q?!TAstx&E-ZqY;Py}jdylXOiQmP z>`%L8p2yXmgkX&Ew|_2o?QCkX4gW;0Jx#c8-hsAUgU-O1Fd401N?H2#=-Dc%&5|>= z^j9~W2R(lLPa*}QS4CN|Fm*durI68mrHU+LOcC$;+M^-3^ zu%Ej3W>y^F7RbiyWr)08t)Av>QGQY8*f_cPu~?Dx3HRvSN~O9d$YJvZ=UkVv(~j#0 z8%v&nmT<^rGPZ6pIPHysF#j2~_sMG*l^=I5WJAFewH_#mM8`?tS??$DLw!WZ$&E}F zb#M<_sF4NTN_mUVjx+DWI(&@4{}5E%NwGSxd-v%^W?A5n(*U2FGcQS6$ZH+NP;l!E z&ipw(!ERb%r7_U0qk<~O~(st^x){~D`V zeZkYi6Qa+m?~b{-#KlVK<$x>E8e9zMzPUjdA5>k?hUhdJsv&`&sjPl1m@`yt-V67~ z%h<)1k&+d!9Ly)kC20OZQ|8>P^{FTd@A(HU=U}vz*VDwK+}^0paJm#$uFEr{#WLqf zHLGs=vrCW_Vw;7}R!pA?rn2$~C8)wgm&!2^T*Z_PZ)6L0`lLE^Q6MGmBjraRy-}zR zwL5#hr~e*u`?0DmxsETM>@kL2Do*spaMi+Y=63B%P*B0Jj0Xg+Df|M($cOZiS(QCy z{u}18{WG_|TMxzBygUKsLuDXnlHHmQZv@Pn7q*5f^Z++nBR^X{kIX{CJQvkSW3~ic zc_8LQji{7QnTC)~jcLg9ICCtfgv!lJzWxd7>sBw|%2s%%5Ku82D5#72zGv%mR2LWF zALc>0gqWb9o^nh~^hQ?ZXd6PnVRIQ2k5*&FoMMc98l;C@t>Ta`8s|bCJfpImB;=hw z)^cntmJ<_FyntSl+ZSe}cGS{N4Vi;Am_PyzXY85PA+N26)WRVXQ;=X>d3#1#`-L3i z35pMN?eYa9*H=MgG0MGnc`?SWCZCoH8b?ZR2d|O$tAO?(((zBySbf>Wx-vSAofcS3DU*S^mhIiAonC zzHs&qdpR2g4I2eMR^GUvNxlLZb#Fd%N}2Z!hy4g1lML9?rK&hB!I?&UV&If#71ywaP}y@q97iwv{x{@l;8grWYkHHh36`29iSK$ywf#&eA>naj^wNO&BrHP*|}A4pb6_R{pn%)Hpl`<@`2*D^cW zeEda9w@dHD8hnl7pu&e7eg{w`hV&^9fD^1NPK&VR7zSB4a=OX_ZO?M;dXf z*$h!;kX|(NIUJJsRmfd`x@<5tbI=-1n5=#pj%5zmy6%%1yvGxW*=OHXt@H=qpT)+P zqmVHX@}%dBeg{M7j6xH|AwinmU>FR31Kl!RUpX@qQ&dqyxy{57QW`doapIt3s0WLJ zbf`*ii<3!uC7XkkKffR?A+7C|f>4L>xots!Znft)~pcVHdG00*~uz1_sxPf$wy6c#C}nOd$cD8U;32h}O| zHVL9ky+C1QTB3$*FXS=gD?N0=d3s^Oc9pLD}=WGj*8_##{*n`GE(AZmrU9SZ6Grhttw6O#;K3-)4= zjpmDrS&9fwP5n-IdfH?|R?qqmmN$aTd)oWvCNhf-CS)aVw;|i4IQNK1m^B;aXr#VK zFOiRSbft>S-NJkcmYIu&nUj02yVrHB@G!Y75J<6=d}~mI{5I-B&f;d4 z_Yn3FMqx?$$lC5BVcunIWL$4=w3ftC<8gJk^$J8re=Zzc^T`4_?FGYY;N?*52%;Uv zoA7131X%`**LZPCweY+#f_NQ1N0ND>;IbOUk`T@+;%z7>botJKY4Liqa<(zDk@Pqh zq58TA0np}Y@QdqkQZxWS>1so4VmYYy(31xcB(IZ^6g`IwoW`9PkJwp#; z>@zT9k59x%uLD0aopC=ryhfwE*& znG9$17)}pqGPjKkhhHV@4vdSvC7H!I0zprFFpkgE!D$>sa1PRL*cS|u{sQ`Lm@GYE zp?HetWA+rgoK4e6sq47i2;{5{b!0CM&RREL;Q3PYj2j0lZTZ=>*ie}WmAY#+q<55l zsz$CUwMkijZ5y`~nEw4F@_V*dTj-hdJ5LNMYva~X0-wB_F;9V7@0TNkuRZ(@pRhu)?G;Cw;3XZO}#; zZt*ySfEaFb;+X+s5{iUt?DS#);{;19ORX0N_hG}DKV9GQOZt?H#{|jjWo$lvpf4o{ z%r+@0IhJ9Jikm4Uvz>(Yi$3ua%`&x9yNOTfJ-fKDAK4%$a7V!boi|e44-Qo`s*7QP zn{r;2=Dp$!VpQCP12=3ew3^x(^36j9xBxN(){q2nG8+bka<^oac2JL9G>L} zA#p>$Y=~?lO~y8syT#=^dGfoLbt6r!aAo>1PGvoO4u@vDUAC$z73sGma*<4Hxcmm6 zpcq-pkSMMZ0aMq2w4h};l2h-flV+V~Edj<1idk>hJDwRPQx({X}PC&|WB^h`YQ~ zv}G7bNCSb)g5;ifBw^@sGaUK8=>^hJ_>Lb*oE6KMm{Zwhz5}QaCju2u+X<9tS2L9a zIGDR%At~okeJmQo8mUFWCP#$8eeKWxSzVY|hc}XOz9B&^wBgl{uPBX74raMao)B11 zaZPJ*Pxc3zh#+XdHMCpRwqBj2WiL&1L3cSlkPn zh4b8|!-Gej-UA|7Fn%dNYGGQe)Y_M3%t^InIEhqo+MR5pR64y zt3#g>tDte2XFnJl#EC5Q0$@NG!=CRQWTUh8;nJduS(95D(y7mVHSf14*B|E`~Fvn#K(c zwKIIm_`8jICJb=OSpA~$ zQ?u;KE^}5FKgyz}9hzM=I~;ZtwW!ATYr3Pz(5{oVk{?X$=h?b=FqBCrp|jnEpGNv$ zgc_>6# ze;nzRk>`*w;I{>7#o-VTsmRo|*7w3Hv%(yc@U44Kqb7y;IBMQvg4^zc^z-*#SbKTL z3#!ljEbTtXc|||pW?uU`WR^?5ia z$CDET3p*Nd2yHSrAlj$ayG%V@$)_N;%N?{Q8UJgHvK%pHB(#nT^q^*(y&jBy^mYtv zKf0P3=(1oGaOp(Pv+ocY){G)LWU}?inW$5_u4qbdxkyKX^kVfCk`Ooz#8movQ7?T` z``0_$SnUdevCWU4dQZNtLNI}kYu#pW?I)6eSutTE=k1Mn3_6D_e9)1j zbQ}a$>#}>QMdG>B-BEiN$@U^l;WG0cAkN{+kA-UOb@bW@tVf$L$7n26a~a~l%!HfQ zK*v~dg=AG7Ag)5pA%yqy9KL5|akv~%af1#%o(U6v+cXj0_o&5T9Ij2wjsw251LA?9 zQO#fk#4FlYIL2ZE3XGD+E)fCxB*ZF_1~%a>vYp>wca)@k6~@)DwD23D2|=29{+-Zt zHPp%V?Npt+oAo+L2tp868@;x*1Kl^4Q()g&EuA+MgQ6l$%6VqQdqG62k~#cG^6v>e zf={o+PHQVOnI0`93kPBc!PP5o86iDQOljgqDB%p!Gt?dS1)COn92QJ7Lc^@dET^k_ zv3Evauy!0m^|r?}J?7XG+fRIMs5_x>Xme%po#B+p<_DoE6Jo`Dm>LH#sZYSIr(;Qx zDrw>H@S{wE7jS}41vEw5>ir^JBvhq$uxh0&Q4C9ad^CwY65%CFgM~eD zHBqLEJs#e4i*P0iUL_zt4gi__eev-Rx3K@~i;yUDYsBmLxLCiX7x`pNevq zzpr=Df%G3p@2f3BqltK^)J)2nF6P&ump?Qi~VH%}AG4{>*xDl8AQwdep zgG7(@($-;SH@__w%kki)5^xk1W|OL(Vwb$S!a$~j1a;PS7K44k76k(q3-P}5)enIL zfP-Nu$2q)twxaiPdnv+~@>SQ9S0mJs5pikMA+NC^p;hvx-cj<((Ztq!qx2(u6IOz! zItqyZF9?3Ln)o@;24<7r0DUCOb$5I^fJ5tiF97vA@qJ|X04%E()uG-3o$tXjJipOsl?&&!QG~iE`%) zA|d{9%O#Qaf*RC;EwO&UsuJVwDf_RNFzPUxisLanPW5y2Tsk0peh-9%d=vPP4yXbI zy-E=uNa3SLl^OXU2>W3)Lknm66^ebtOJtpPsA1^JW|bmInkbxnLdw8kS~F_pRP(lr z)pD5ldpGNjRb|cWtd$zf_qT5IwHP|Gr|aRTyES<0sfP{gm;Kd;he>$#FH-}?0x8i( zhlN7xrvkuzGpxG^wK#FVs3d1&bbZFaUb6PF`e255(G?GQoWYMV#w~uVFfK^2S+d>qIAVLDcO^X2o8}50qKBD zPpj%TTH*+br7jZo%a(;HHR@9uoEn%KPAn|DCKhI!+kQqg5i`ia?MO`~{7;IPHfDgE z1-0D%#!jTGGE$i6Aa^idR(9uq#p=ProL?S*$mqXJ8D;i&2SJpRcwQFdp{6P=Gpjf?rDdyH2gJaM2<#Af*9f$vJgM;- zQDjJhG$qJ%noy`fEjQ`0F<{16<48L2Q>VxLVJTUkTGGqCI)D-mMk z9SNP!Qyr?b@8yBF34`@9(@uL}8(8_qPP&}Z$p>BZ#QZOvRlZh}jIS6SGHrS>Jkpk- zPK5N!Jg_Vfl*@K0o_`!1Lav!GSU{CW4*sa{;zyyl!Yn8AL;7)JRgchpPK4$tL>u{w z5e**#l|<_{VUTq3og92ya5py?{rB(Hiww0ld0uQHP!|Y^y{UtZ2!KA=HrbeC=JAvF zyD-d5V0~?B$D295AA=4nyzIumU+Sx*LWqaqIym6YOLEc-tWLtyR#nvX_$^F0(5E2` zzbXmzy|$OgDTaaZKPjOt32U`spMoIF7Z*`KwpyU?<3(d~rV=~asAzS9`uZ8sVOW%X z2y5x_s!A3fUpdCg^UzXeUH|I+ymrw?d@3xjK0OkEmL}6~6G{#7dR6Z?sekOgz0MX* z{XWrN)>TS|7`gR8JyMTXs>_5Ko0aEmmK!mU_#$c{#}K>+M7|g_ncbc`fk-?XMp6Pc z_LXYz_H*uzXoJLJo1ki|F>n%E{?>cf6y&rXSS6( z^LuIV zA37*9B3qkYAbYcIE=}}C_;LFocJn5(+9#Vp3rIvx%3$cG>_BX-l_0Jho5PWpDOT?^ z9KNI}SM?@0rMp^joDylHtS6%{~!Oh2? zv~#R>FNmKtoAnNF%6VO#nFOLuJArbrjB)R^+431z6F9X{?e;c!Oh&<|@I z5enSbA(ML&%!FM}TbrSXX2`Xhzw}7kv&8JVa?$YckxPnuxVv_at=AK$ffO%srp2^; z9#&mXX}omcf*L8MV2cNjVtOCv7Ff+NX+idJ^n&oABoJqfmwTc1R(C0_Nxpx{w_&fE zk|;-?G?#5k9hw+NVWg#(p3A$b^UdB@PDF|Lea@#RBU^_M-k=1?z0aCj`)o3J)VS@R z`EimFHL3LO8Y1>c9J6NnttCFgwuY;)ZyWi1EMO~-P*hBH(ut_?Mb_s)@+n94g8aKI zB8Pra`iF&yMKl=NBodr0q|w8Zj5JK96Lngo3J|JP$UBCZ)`^8CluAEWl`!oYRMPrx#I+ouUt{ivV*dmmMjd4S0iVL}{sOyZ4Iuh{2rth`V) zU2tidr7Cbw$3m-GV+UBxglb^e1fa^7-Q1=sLFa+fuMVI3KZ(yX#4@0nUoZ%9>N=6W zoV7Y~!m^G?;BZH~YE)l4rM;X@VZ|keo5FYIatjnhRqOJL)T;kTTq`4g#Zl_urY%gD zLNaYW_ppO$h1_OD#mHlg!cM7Pbjp?`=c}PzK1YS0-QMsDW#x`FdeV9M2fO6bm#c6} zyU#eKX|>PZM?aH3hni>>Cg9p4N9(tHN%Q)(uc9Q1B6uU}klvF4#1J}Ahn~F1d=siO zkYK!g2pxHtohI?O@^R<6Z$&Gb5v8pdY)}iH^Sccizk6`>rCk+IXdky#n}H*Hzu3$G z4V5q_)jrUtGqzX|g*w8(ml*oI7L3D~BJQ|S{JU1^56+|_plBFAu4M_Atd~`ob&KLKIcB1r zxrF0m>snSyPzv>A60fSJKKfG&Px4gOhO&`od$M^NJPs?J;AQ0kBH{;5;+zg&BrAB$ z?5ErhOeYNZ>+lYNP>^Rd_w>4`G(YGV6~p zx4i89(dXq`4`5pKgj#`4PQM&pDtj#L>9Dk;S`XSi&+lSWH8OU#Hg=||$5#c)Wf#B8 zR-sHAXKhi~Et_v2jzdVif{x=0*267k96bNKLM6OUIMjMa3>AMv_eFWBGL-R#)@6#pnd|(idawycn3l z#bA1o|BgSolb|3s4Fyrq&)MH}47P=u&2lM&6-JN6VK=#Eluz9ls@spq*esT|iU7UYrv!VNVsZh4TyL1B%$c({(j9l>Y;KxEK%o?3ze2>8@(UIRP*YsRyKYpOZGsth|4d=j2qO@?*b;z<_Gc>F3ZP>ns_>U2#q0B_IcUo3+$fQ3dJA^ zYhZMUQYpP12o>-$E7)&O2|j<0N_cAc5e`{sVi=YtWr71OixDnM-beJb83VOxIj&{d zeDSa=ci9-xfAq*S&^twW2ro0bgjf7EH<4CzaLXmq5k;KrQRP(e^WJqYk>065H4A%G zf^R|0t|6P?PGUp@Qzh}Bg$kHkJo7qQ=2WF%eLPZ0phgy>85Ep~RqQV*2iPAXh+h#} zjfeY$@e70j6CVhihUD1;!vuYp_x18 zBg%%9amBX5565u`(Zc@R5x(5>C>w(#Y2#3*)p%h@n>WD~ z(UZwf#~HQh5L^1#g?@zsIYRpp=noDZ&d|@_AM$Va=yWmdXV^MV`fQ3MH6`Eyj~arX zzWz$itMl-CZo(8Uy?hc{w4>trXTrZ4f$u5vke#CYB9yn=IN zEjVOlmYs>on1KEM`H{Wn@501NC7bEw&kjr*(`fPMy%=i;8Rj3+xCWvEmn<|0N<3O> zlaqBh$EMlgmgt#!xa*Bn_L9sm|52Uv=ne~Aq>O9|j5W{P$?J}_r(%6xjp&mJLuN0) zXRurzmztP0_JN9>aXdKH{T!c$k^{O6qQ3j&IX&xfmWu%ld2c`;->J$%(uZaV?UuS# z$E^1syi)4@#4qVKh0i&~tDthr=m=BXL1llSfSi+tZGY&kEk=yMB|RB(WdGz{id&6v zOlk}YJEY&9UTw1=vWQuw=hY_D%t3ABOoh>($cW2oh|OduD2d?#j^SOZH)x>BLq=q> ziL9tXc8p!moZo(CBm0;Gc&(?lqVj5dGzVG#n~QU?Ua;-5RW;`856HxDl{ENGJkr4r z*W}Je)bigXr)}9hw9Y|S8S8Eqg0dB=k={_GvXcb19R|o3OUtlp3m!o-y~|b8PK?zY zDHsM9os^{K3`uO=QE=IWLO+K(tUsx>wN_0P1`D`U-fCy$VU!GOkaXZO;miLP)BnUy z)U*L)P>k@cX2$EUf&{&2hn>NvgmRKStuKe8UJ7o?VPsCU78Ap9T^V+rQ+R1wZG32d zfqCwYPp80b&;AAfD20LQYF-EBX$L8MCKADm?-U8Rg)pnh7~dZV1)y~Xi(^q21zAp0 zT#@H}43(<;k%ppNm+(R)V)gZYlvK1_tSWEy!#HO-J`_C!uvR^F&lA@pmH-kXjs+oi zF6znl&?qqmcn3xqi#O1ZJZCA z=fI&ZrVpli2GHOi9F7ORR22S_+GJ??RaOPP-7ZlYC!h12@G!Ncx!_g)a2T4>y5Uf? zuUfHehoLtOvX0MVq6u!l6c;=?YR%E0qjzT=ojXrO%4h38mYs*$s#|#yCOIl*A%k%G@zlm(#40Ox$18jVzU6%rveg|3JuYdrL3S?bA`_dY5&Utr zoKUG}!E{Iov{kf$Y_eeWk7>WLRxQx@v^&8g&V$K#z>PLemx;Z6TM^)tt5hpd)9Qwd z%9B?0jbN6{T@Wtt?Lf=YD_6nGXl@$r*WN!uQsH^x$mhX`)erU_yX-7@F?ONK45~m^ zI6pG|hM}Y4W8fzHydXBcIk4wTHR^g(Q%6JVZftoNDD+o3jKstQ#ZlPIHP|3+)!mO@ zb6RIhzlarKw{`PX4?XUqP&^Co!K33)I?MbdFEl_h(2Rj6rkGI3F{mrUPrytE_xc&a`5IfhDvdc|1JCyft@PlPipp1fQ7wk`0z zgxhFq^|-`$)IWPMOlCkyOOuioZC&EY`3WYuC~`sRsx-Z)#cr6_x9E@U=+8bXPbPn` zE=nAYsy9no+D8BMO5}sO-KnpwQ%k;(VV%X36P@?{%7){6s?pxj_>Vh2GDV4nuNZEg zL_Z&d>6w*J`%EsXUZggvl_P#+(MOg0fN{C!u??3zLgRRW^=IK~AB947+mD0`wew`P zi_u!MloE22bvuYiZRsWT!rjQ81o>XOhAM2hk>CyWg0XrG(u%!O>kK3*ewJS()g4p1 z%#`L4FK5J&2_`Lk*ryZ+QI15+mZ;t#Ru20Pl?UW?2C=Ru5P$x#^{Lkt>DaE$sI&ly zApD){WI1c^5>iV+Rjfj6nqP>>#|GTdSA|jh?s}SFThge|(|E}ia3ANZJ!@qjoqM|xZ9|VOt z*DM5My^I5cRh6~Kl02rfnC|xw*VI|Nv5(EZL91w#3MJ=DqB#@_1|2EpQNZ#*R3SK4 zl7;#3tL`!La*Db&zn9W1qlb>u&m9UFA=nHCrsqBdd_@lx{V^|FU;q7V6`hN*5|ch5 zR%N9GIM0{MD&eaErQ?)Vs52P?C^pNx^^8>2XkB=xp$ZgeLxDgRsAX@W_X3wS30w^e z+ysg1Z!Sml*@ZaNR;!a3r6I;Y*2WApAq^yXJRte;q{NMG;DBkVpJJ;KOB2pEj-_v} z7NXAi4O{PF6G!rTs%7L#m4r_%-r|F2`ZG*?KFf3i7zi2Re&2o2O?=Rgk}u)yFxw#s zlA0L#=)>p>NhYAJGq(DE_qH(J`W0I1LE>T!szi#S=+1pWT!Nl(s`nhnE5 zsv7b@E}t~jU2zH`Hh6-6gWH($JRuwTb{gO$n(R#8CraMO3vUdf;>|9lMLSR@GRug0T3j;`MiUXlH{XhV-xxFoZe)8| z3$~Y|!ymAb*zRVwoaJnUSi}AB{9L)QJ%M|LlTaNQx1kU*&-cTLuqS+5N5?G{x-DKd z>_>~P2i_4z&&LG(mt0yRm*OQ@D>CQSX|I_Yx4sqQU;HGCRpyu#jI z!mr%n4hvP*MDS_{@`l}l9V$nAT|R1+Ru9Vx=4k+IUDyof>uA) zE9(=b%)s$<4pQ=q=35_tak+Q0egxhoz65q-65M)D|L5K5iq__aR;I51Ts#~-D>JQ( z-u`x(oq+)yGp)c9A7+OYaro;Xoyi$F%{vX&C!&g?( zCbImb-;X?(p292PG2q`xwO=A}5K>w>eOb58)o^-Xd*yoAK?TC}ZAg$Od$@BU5qjLP zN_UCWs%tI;`XgzJC8(2R76T20J)`biqgNmB)B;C+WtS1Invuj@5u4?4@fK+LJX@|cFgdpeCGldq(eQ@ZL?kKOUcRq-T`sZ`zm zefoHOfrvW^_l~V&Kh))3ZG@~C7|DRb3$yU}+_5S;Idb>j$=*)eQ(O*+gY?Ztb3sZW zonl$8!fpc^yJpd}%8GS7E_S(+=j14+sWxZSP!4%qm>s)()AbI$j$W#bGX-M;<8B)g zt4%-BWkgM(&}`hd{;CU=DNU8B&g%V4NM+b#Wo=2ps8SU%LHUu;(`!I*etBb&O;qIwI zCsg$$XEMs?#aJ;)!eXv+^F?hE0>1K_iZu#WlaKd=XxvQSFG4(huKyh?t3I!OZWcpADdO&a;;z~bGOvj;zwH+YUf%s z*oo6cTF0a?>MRLi@O?V66ku!oO}%|1O?JUJQk5;jMIsnX!vuQiA=|!Hhwo)yWZ#Qe zkoLDxrT)=%A3j30(A0cIwEhP9Dwt7!1=84^_Y3^y9*ga_lfA{TaMqMZ?Rk!1uP!MW zB%f|da&69|A^s;`Cw1e@?VY6S)SmCN#9Tfy_w-kR2if7f{#8my zk&i}9S{V5B;AXY(aLZ5`;6JDUf03{M=U*ku6FBzvXEiB4X)$3T1w~pZ;eQkAv~D&G zq+)*+c#!XW`M~e`)|NNgyj=t4?+PH-HTwRlVXAL!Wnpb?^V_PxHuJyAb=8a8Rqgey z?F@el!1}xXA8peDpI}@|`%l|{0t}sXEp04rg4k~9`#Q${S*|59{XOXV0Ac%I++A*Ra2R4)-7OwGK9bKKzDkp!bUc(!9Gf4uSc~2>#ClG5*Gtd6EK$ z3H%S1owbd%y{?6zu7mEMFQ9KrD&7bNoeU_l6A)M6Z#3|;%+r|V|3fF1{i`WH2M0S- zJx2$_dz5bMQ~hKMXb|(SZyx_{v&_?g?Y9jAM2BDdaNFa6asOAj)^-%fA4p3_D^mxT z8=Adc5AN@3f4F?@je6IP|J%wp2i(@LmGy0II`-|>ufG}ivs_D!%lU7q|7iUh@awp} zjk*4Y^e0B;cbI><@Nc_D^*8Yky(Irv*UW4{Bb#!AivUe zWV+k;(o?;0SAizPfNlZ)`%fwJoCb!||D!1Z6GMITdm4EUf(U8>#6WK#2HtE0Md<(4 z$bHf9T4_%FILeYhG!#<;0b%{8AJ9dCvb&mYBT2UuQx6d$PNhuDVXR60iJ^LC>8X3sE4+yLa80h-gs=rH?r)J=P zLOa@7U7t61H~nK=^@Tk^E&+ntO?qPRf1yj6S~=WLzn1lH``dPOurbe9&2LQ z0MJ9;FNRC_pDaMdOn3L6KxIL<5t!Pm(Qg}0Ao71ncuoC{;r`wE>no)HEZ55e>E!=` zX85J|sj_EU+(6F@!9YML|7HO{vphrpH|$zahP(T3hC^>H3QT4R1UH9&mM7BN|0(1j z+}~(`CsO4DJ+MIW1a`$S-Vi#s@V~*Y-HRV^;Jbw%0I_UF2V7zo_e?-YtM8ZaC;OkL^|!muHm&ms7l;dM zKwKdHN91d;T>brEK-9a5o^tZnkiV6Q_z&?~nI%ns5)Jh&Ol|B9?X4Z{^lz^I2yWF! zyHS7n&iZEdw{q)i$N`!90zROxb6^>EGu&Y|-zCH!5OIJ+ENEz?>uBL1s%vFnai_lk z^mg{rsZ$_bNC0L5f`3H3R$4&&Z|Qd!7r+4@W$7CLDq8~tzByIZ_x%?4M{-Gg*N6wG zph&)@JHUW^2TaJMH-t19{NL2OC2hmC9YF`YMHf)(O-U1`e#`u=I?-^|@wEWz1>l1> zsi(8QrAnGQ07J*(Zdth@jRGnF>JVTkvK#$RT>LFn+R;+)KFi0w*T&rjOr;EnN^t`k z1LW}6OX-`={f}SC=$RSnJKSfhS^UxuOn|IoK=}A~<_v_6jsJrEW6QCXfuXbFJ##eR z4`$YLj7@;(T0k2&!;{SRe`!O?@P4(ZHcYC_!GM4?lib#|=H7o`-)%rEP!#%oAcD*Q z-h0!49^ZcpmDRPgzt4avje~jPfEIiJE!>2b!9Vz&0snlsf48KW+f$mTz)+h3R#!KN z+5pmTp?_>Lxtlrjar*N(Afz)eo7@zX68pDI6}#(EaW}LV7C!$3=)Exj22Ax&0j3ec zd!drn`nnFL)_2X#fLk$^m7$jb$m`=NZ_Z2}B=;i!u#k|mzM;+iU>1m#I3Zw6a6sH# zlVy3nB)=bQXXxPIB5Mbv6Tr&opWlC{6SaEKzG|QY(11>EMjs67|I*Ign&ueChS7fj z>^uX=H`RhpcQ5r%F$Juxj7*L13l&xE*tC@Zcn$#Hj6kjQ{|S7zyt5b^&3b^g-2gM* z%sZPIe~UG>GUj(QGP=v-B#j1cWCMU9|0>tnfCcLVkUt(sIp4^nZdU>lo_|$(^Rtqv z^)L0F&LDp_1a#8{=;r4W=<9j8?nXT^ncw){wE!B3FG}?RNF^{MqyF7K@H5L(gZ&?= z0RiL6ihBTvf^4v>0*h38FD70<7v`+WVn zUk;awpZbA*t^U$4Pr-kae#f}(3V`^d0I}(>a&1u`k$)J!B*@pT2k;JqvI72<2&_Yh z|E>u9%c4vJHL=mi<;?})wTysk{akuo6Un7-%JN65^v6-` zVh(o%$7`5!SZ8Pvpco85%|tiE(~-Xqc1^q&2>-c50UGG<5TK@;(N;#~KHy(>9^WCAuBVGuIpRhI|T70mQ$yI;dl58 z?U~P=G$E_s&^o2Um{0)!fCY#*d#Dt87wv96-M&KLXAjdNZ&H3b|NR#V{Chcft-sr6 zpZ}x_#r!|$cRc;Nrr$n>`X?Pd{=d`j*30dqMt`y+QtxHojkJ>MYmcWDMTK-1#NbzdMKIE+>C~ zwiP}44-QC@ew%GwgYM6^7{~t&x-Un%X561`bxr=8@%wD+nsk4*6+ZVX>Ap5WIn(g=E#lu-F%#dJ;#|Y-&zYbO?t|T%GhGAk z&za7T?*slOXSzn-pEHSF{tx7@!|@t;f6gTO=;4hR@td6K8gzdy@Br;5=>MAwT+{E* z1+p>!AM`tNfouBxxqu7Kf2ZHA;QMod1EPD`ccbpl1qMiNqHfHzcf;<_1s+iS26lfg zaIMJua{(@z-$3t-^4GlkbAg8pck_Oq3tThr&jq4b?q>cr7q~{=p9|!&-HW`p)A#2B zC7gHD{zoowE#m#TKquF4pm!{7u4(t@0vbGb((d-b`*VS9xnD8&D(wDT0955B=AK*t W3|QC#Z~TBiM8IRHWA*Dt0{;iwCE5o7 diff --git a/CPSTreasury/build/libs/irc2-token-0.9.1-optimized.jar b/CPSTreasury/build/libs/irc2-token-0.9.1-optimized.jar deleted file mode 100644 index 17ddc4462327d67ea26c65f78bbec55441ab6b55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28280 zcmagFV{k6*yXGC+wr$(C?PSHaZQHh;72CFLJ6W;b_3U|P_S91~``=alp{x3?tGch> zed0LIR*(h;K>>h(fB*mhApCp&_kjWc3m_}1B1kJKCq^$TC?_cu)6K=G z3dH8g->PiXGXztKTda(7Fy8o5S4DEG+n#1G$}yGwUHS0zZmk3zBOEmOo9_fKn|w>h z84m1l*&`M;75qgqwSKDsuZI@%ZnD05?kT5tvd9XMx%B;BlbFPA0<=(b{l#wNps(Qn zuv|=03>*#w0008{Kd}t{mt`rsU)F|BPXA4@CbR*{aWkJ;Q&x_3D2VCcFOM-S#UyK> zR}f$#kZ_PeVKhO3h@@>vjmC9dH?sh9S~V-}X3I_O8iQs&+Y+rh)j0$spJg>|tLqP& zs+N}Ll9uM08m;!z&&RPTQ#ONJRVMCJzwDpS)1R5kJhNSFUl@RsH!K8u69fdqPgj>P zF7g^v&(rGjom$dA1S$%b3(eP;kC|E&C*Y=!5Lo>F`OdM?v6pWurEY*OI)Qu27DFUO zt@_KY(-zWCuEx$a>XY<)JGLMh8m=|^t=^KKT`pN9@$H;~G@Xub)^yqmiy^f)Mvdx= z&`3*;W=I7q^Xp}>3ULFxSVC>o3DnN#rQy0EB5ZY%3<+Ld2ttLc*4YCw-4KUY^Sr|{ zN`V$zJuw>X8=W1@!$41XgWZ&-DHBg99W50hHb^*=F`JUSrR604nUsIbJs?dT)bS&> zY7#w>v>K^1WXn`9I1{`UAXFu7(nyt&Tc40$gs2SJTkL;@g3z8>;-9Zr=1pE}E*S7> zFEw{9dqc6GrjN?8u8KN2Tk_;!)3;zDuN#S_?ZMbiC0XYfU1XDv8|zV{42`4UOuuz; z)mO)4#yPdp;P_lc4H@GWjNo+8q|6O(z14!nRqRkOVxU>PoP5Gs>fLegNYdk2J;3>1 ziExbY4tAUUI-~Q2xeMywta&KP!iV%lc(~wIL(Q_MU6+-p)=8fz{v!%O&X&Ac)l}jD zEF>y?2!^@R|Bmpw&x1)tr~%5iMiFG(Ws_(KOLN#t3xO;~ix&)y7|6Zktf(z)p0_kN ze@0jUqie4S(E@Z`yU~zEFh@oWg@wB#QZ^R)MsG0Ba#j&a@@K-nmQYM8v}8nEAK#;PJy&WgoYNch({ z;6y#LYls2(+`S}=mk;gBoT`{{OIVLX3E7P(8 z8M>;W74`BAV=d~biz(BONKW|Tw5&E?f-(=7-2(@vB25Om14>LgO~z8)K_BXu|+-j=8xue{sP{ zk|G?@!eJoVGm!~vNWMCNhXv-b=Z^Pf-HLA`zclVw1r~$Ddp2BGT;|DH)Bx#F*I&x| z#=`jxt^~>ZSZ%3@uKZ7bxV#`*S0vm7QueKb)_t)SE;)k>!Dp{$veETTWwk71u!?*1 z-0;_#<6MW?F}Y&y2bVUrH>3f@rs@ZaVXC6{;}q5FswTG@a7|4(Mls$|okm^ZMeXs< zqsy48*}(W^bGk`$AikqF>Qab?t}&d!+5I6cJidIUkT@dhMzj7(abp0lD+>iD(>uxi^>IPMv%dCY!sIHGiMY z*i`&RGkL@4!?@P){Jtvhj-!ye`xV?Y5pmh@yr8SMS#T^JlrZSl1JG+Q z?`JU}IeTHLMbKjq49-|lUbf(*R>8>?4O(JzOATI;4=a6V^)T=|y}}LC_m@c8F4nY- zSR}bnPuU_S?jK+9UNbO10SE}M_&xbxw27TkmgJmAuCD&)cQc_nD}KRO>SH|3$j>aE zfpxzXrAjf(Z!o{QQ1*R%l(^|+SJ^m_9}x}3j`JUAs$J8XE@3|T^z4S7`M$S2F{;AOy>lB(EOSO9>FvK)Gjq_S+rxpzyiUkYyNXvxR#e`P0 zQp~Z@;2XSh{SdcqR0EJ|%f{+%p)*g_)O`dxd;5r7-@P+Ia{C8Na%N4@qkA%`Y>^DJ z*Yv9=O)xvTa)ZeqVW{9v zlQ}#m;F@Jx);g!h6yg;Y%1jD}C{onMU!>i!gcjGHm7yX$pk5vL1~P7%ubh7?OdU6R z=t|G9C6excNTHLtw;)k<$qjfdhd_bc$zaX|i=rspS0`lema7M~1*?d&!nEuwVWJHp z;k9JPU((11xw}fvtL<<*$_C>uw*jdyXkKUvV_DPebp}+_8Z*{8j-kYW4vuxI0IwI)_L~S+c9y68#%7#v zOR|@pvEp9#UceESDr=pjOR|R@Sk7&6K>@wekUQdcr9Gumh`7{fUI~G!W$)78^siOS ze_>~_wMcRRwk4SjKP6@vjfw!d?k!6v)6raf&{A?2+6Opn0Zz7W0up@IO;*9W)BzCyv^ZE>C@00#MLOC0&zotnCRe$ zZmBU<7pAPT4KhdrQoX97b6czQNGKy~MThq6O`X?uwbc23vH%_kUOV|+yf`z32Jgh| zrKBTSwm7xc7Q;+?rxfhIKFG^;ctH_VF^K}P4~}>eYe<-iPuGw*iCS(7I*s2XhOr1z zt0G`3A}?7A<$a!bfk`3ia{95=W~FmJ47oo7yy$FHMEJ!Ric?_Pa|~SA5=|MaU_MmS zl_Kg=6~VWXKpfMd7T|Ctc0q$SiGyR@wR1P_(AaZIT7g$w$3ysYhW)Ra&WBcV6SKjbGNH#nYD6`l@g z@Uf@9*wO!Z7ab8(r!B1S9CNeK^z z1mvB0&o+2}sdTSo7mn4?siK=Ed)r~FMXnq}tUL9LUqYHidxWgv9UgLjNawQ9oyOdS zhq9-6?URS%M??8`6|;l#<1E^(z^NXxW1T;%I=#RiLDW6WA4TTv7YvK2b(%{G&%Meg z7Lj+ETa3uu&o@KDb(wn-!9UH9BYy`0-xhE#3W`PCzREX4<{cHx6Zta^_pVYX?=<%q zo_m|G9iayR9fDUbR{DG>@}ViB%xJx6BSIfy!q%OA_Kfsy4c;Ai7K`L*0_h_MxveQw zM^&JnHfM$NN2_qwWuEpZWJNGr%T#d^sXYG&P|k`A0z1kL0IFdvVl*7UVAYupyAJ_)!SH&8lsuTii~sofHywgpTNcr_C^j&NeM z+zKoB(kSR|e2rlXY7fIJi`SJ-k>;@a%l?Bf|MLuTtveE}UP7zH1LK*~l-L{ahS5x( zRlRaQMdCYM*g4p1GNyBu_r}lKqBP^sGE3r$J^|(?0KSjTX%9u90D7J98Th0ee6o>y z&-5i8y%V_P3Xg8`CO>QY??q6_66YF3sc( zC3|O`XM8ud zhTg;M2ND4uvm$XIVT_0t8uHV{;trU6!nX0ECBW@-q9SDNFojnU`})oW@^Hvy!E>U) z9(n*aSc*j2J%|ehwMC%sN?^sie}YyA*7_)HYT;JkjTFa(f9#7YRfdE!7cg~U>;eah z&b+o_zz>ot$SOc8UVC&{s1G0vXA4v3(B@tI!yHsLSTnSlN+ z0#w~8RdCJl9I@Rx8r?fZIHk^jN0h=MQ64a(uCB)&%pRj9WO{g!>DtNC$D%;&Z9tUA_8+=g!U3-c4eLB=p44C3p)o5es&Nd zUoJmGI#nS*FCxGyL(`-~9^CKT0_V$ctkR%ch7$S|7;X1ONVWW_xlwiI(y7Ct8U(TNTB=FYQS_DYtgCAp-F@mAvvYXJ&$**tXiQUjss4Z{@L1pTH z(+jklBHNiY$t>!YVjeiuFfOOM`w)lzoKF)v4gIVVlez#5P4GpG-Y` zN(-^pS6IQMl~&d{72F16{d#okJOdneGR6o!_wUo#Kn@Wcyyj^+Vut$mTKl8e928;v zRtC=q4pVPOgx(JH5ky(a$rP`vyJwb8QgJx`z#hwTck~macdD@k#Jv8xtXHq_)Zz~K z5B&a2Sz7S>tQxtmRxq3hT`N*rifk8uwUVchO+3v!20`#UUScdQ-6$h8qYM$sXnq5h z_(8qvz{d00tnr*y2=yL#z3|ttJF}oyr79FBk}t1(ej#gL*6?23q1~{1_<;sC$IU#E zO=&~#?K7N#-j>9}3ZgPmu=`dY`$(%3{-LQ2GPD-WHIKCm{1G>hcq6q9S~R`$%x^o! zFOb!Nuo$@p%cch{>$xyI9r2lCmU1qc1}&r;n^uVaT_iz|*84c6>|qv*>&|+*@VcpL zAMn&(*k+b>v!K#`nx4|Ajj_9}P6>H}GO8i^oNcazq#F2xl z(IO9oqnUF6Z$hh^5Z5OT&sy)`_SHDX))NRPI~?JY`(HCD-pJOp+mtZSd!<}?LcV7J zJBZJ+B;GjrEZjIFnS}aB0CZ|2)a``3(ZFl9GN-M-;03fYEPA%fWRzT^T7jj8ygPL* z7P7$2`Gk4YY{5lvd&p4%KN-=3qHz5I z#4`qBMkoLP2Mqs7pA`I;K53&kX}c(Z!izlGa447Wf{b^({P3rUg$IhZm_QIziCSF( z#AQC`Fmq|RQTjmT6QQ~hAOb7`)F^C7obYDKeQ`iS{dC4BoAYJnmVeg|K%*ZS?0E`+ zc#R>SQN|ALkwzlY9ideEW8Y8$lZhL_mm9Xpw^JJ?v3j>aB+fdFhG^5IyoOX$iO0m8 z^Cz`)6DIS}*2zA*QDN937Au;ID&4T$w1|b3Q5s0j70Vpa<J zrlJx&{xx>cf&UXQLjM9LM(NsiK>@>8PJ2bMlarb$#g(X|1_jrbl+1`F)_lQuNQ6x6 z#VoAWfE?(Yi@0^4^$JV^4C_}L0R6;kE^}$t{b*)(*R02fclKiozn@PYfO|MNjI}O! zk^MMTH-)0Y}`^s4I{x!kP~m`jlw;gXR;OC`w0Z|~5IQAKvCT!u3`#80E3 zblV2QfuSxy*i%^yjFAhv(oiu~MBtLlLK7o6 z7&i#i@;aqyPyL3y3StdCi{NOpABmWFTp=E3ejT#hJ$|BYA(wS-k_*B{WSdif4)#!D z*Bx!k-o=)2@|WW$g~;29Lk8#<2=k>jD%`Zv*sLQ8xz9gwMZ&S1`xLa~;OS+VlhN35&L^moc6a1Q0i`646m+P91k;x|9o1+fDl4p~}diPjr2)yDSqU#mo zydNBA#G804y6AhAF4+HJsCl*S9_+6vV)7pu68;xMCJMUpiv}pZJGQ#5wZLk)zH`%r z<+@c<@^{pFZ3c}ZLO`L$`=J{>wjm1%HO!v?ej)C^x{gPNY{Zb-SnkC!XE(9J(@(sg zcxOFwoqWH(9bgO~XE8K{0gLLZ35FGP;yiuV^bTW3y`VQ|yuxz1VBW0~R)NW_SCh~H zpT;wdH;uVrGERNZ#OX1lPJXVNVMCKOH|O#Vg+#HEuvCs5;}w?TO6+b})7{ag@gdc4+ggZ2D8c8|Rhc41L9sH|m}WU^iAI26VE zaTi)H!(bXSWNHs!ME2EE|dQ`tVyq?O(J`#gGKY7QoPkA6o6Oq6Z zngt@ghflBw4zdEldI-QA>hlR&@&Fhq<{^E=8JQQ)AGnQm_$>KGe6&QE068#WHkL?1 zbr7ch9s3bwL3niAsV8N(J^~S?Mok$yfS(IBNuaB0e2s4-e+YWa{|`-eWUW&Oe`$jM zk2Hz=izXjcO=T2ylyBSFg}Frnzz~Sw;rxscQpPAo0wNfrEW-#4*z{r3(twcya5K;N z^kHj$f;zr8WAA-Jwc&zj)d;(a39oNh&7RHeD-5XjT&G*k-M1M>dcW_-OFMv>J#fGT zHA0XLW-&k0aUIr=htj4wvo^K)>`86l4CmF5{qKHXEG()4peOJc6%o)_9XizP@pe+` z%V#O%00v!1y=&<~DkG3_=%qJ@iQ1go$u-inHQkREFjvJ4*Ql1JJ!K6v4%fb=yIGuo za^tL0B;0!3O-M3x0hnc+#S*dj%7Sj(z{d{OZn`tCx(B=9HmcuVl@ zX&t$IPTzRAA~Gf>mCc!X5zf3ksx`PtrjFERHJ#4A@-w74T&MMmdTCrZ+DiLKO&p+e z<`^rEh+u)~$_)BjM=8jqn`s?Ucxmm%TP?lZ&{)1MJYo7B1alsc-FQH`J=u(7?GK9A zm`nL7sVFy+G0Z?Zjaq?4LzRpke@kvoD;vje(DQf&elQlbhwR@BNZ^O(98r%<8wlEi z2@xaAm@5GjsHhfnn5gKWC{A*tr0YYB7(l8mI6SQi$sS~`(?N(=$S*#|BsZ@seK(xy zjFQh$rWONQPTdELxA69)p_DRBrLnC(EWQ+n@D8#Yx~BxUvzo)vBw33N!p{yc_|nS@ z_Z72W%(#OX2}R};K_0l8KLq5<)v+G>x&|lKmLxZE8mJj`u_%rp9mj6ztrV8qbXji; zcxZg$sG#rlZp0o-Y_1-?Vt5wKkerDhg?{mz%6t4k7T~AuqD2Cx=UQ7Y2To^ zls|v-4O;|2?W8(hQ0}PO=NM_b5qw_-_zl`&NZG(1H@VY8I8#C-Z(vhoR2tmrR6PK| zB1It5QMkvB5%=_S+cO4Rvd`0ms-!|YwrLy>qV+?^387a9mT9-}dTj< zUX-RNG(_uGtI8LJpA!~!!p7k1!JK*X*0%$Yb_aCj$Y^6}qK}5bPJ8NFuSO1Q?btZbJyE<~@7dPQQ6F&}dbs zOUG_P`-BOWtyVN4s!BS zh!;0-XMrP9!SCI+`Qo-f5bLZ0QYo3b3zeuQA_K`fuE3@+{JU@Io{P&=2BjcPQ6Q_G#Een?GDTpp@rPZ_Vp6&#^)Stst*F(sE;2hgwO9bz!bZQ(M0Hd*&=(FKRTz^bSOmroTmV# zAHXT}<$QJWxcT4H4*Z6$^poBFOtIq z$2lxpw-nWqfy2?oynNZhL4{UiG1@FpbKn0pxMkRAw0r!wH+cG+jsM?+TmK*;{x3v) z)U?%+|7K!2rtx4BfpGr=1HlruBOoJfJDo}bBdxxc0wM)kVWt5A2_vQkquZM9-CMo) z1v+g#_j)Tz70u=6f~e;A1;07`xv-wikOd!8GC;^Sw5j!`m)4iJ89uMu@w^w?9iVz} zbWDvjh>^LCh4x-A9X?|Ak>err!}$aU(n{7=)JhmxHRZ#YZA&q$^Gj=6E7QAbut)?9 zsT=U9`lK5JE?W8fzulloz3VbAx?(YO5RuLh<#4@WxxHOucIgkpR~hCNt)&c@92I2EqqT~pg(VZA5%IOLmKFC=GLC9< z#aHuG099zmF@WWPjH8f6w7CT<<3@svh{<(5&T`^8B_h(`h@^)Q!4CycNBN3WfwaN5m7>z6SglYfDI-IL*o~7Ct@Rni5Le$5M;*Vt9j)rxCCkBf~$%1YMj|>U<~IX(3-B=@~t(D!DrOwlCT*|artKQ zrU(sFQ3qUOip6Oa#r_S5gazrUpn?T-J^Jk&Jq8@tLR@Zh`sO{;hi(IMUKjivCzbgv z4uj&Z(HMr@qXosru?7rqr06_Ca{(fl8;&P^4dn%e z`K48`NDO0y(Ic5UN3}&Kd2GHoWIC9A5?x6l^|X%_j!5jmcuw2kenG@?KO<)!IM&&^ z2R>iwHcF1+_82C2=xZVs^bvjlYFSVTnaoc+w_n7Hb0jA0ODY6d2$;8P$k5uw_kjh>P z!?`l!o2@gA%}6q2#Zv~U*xfghBx#FEj*}VHE8cXwrNk~3$;6YL!L%u>V>}guQ%Evx zSioq#z0a*OdQuZ}OmTU8i(A=nA(viH6)1he8a=GB;%y7z(g%rKzZUB1b;ZACK@49b zbB7J2%Y#LOL(Zk%Ju@2E6i8~3zwl0RfVRSb1K*|#MP|e<34i)nSs(^i=l6O;-?eL$ zo={mF8d^8_OrxL&J42uZ-vM1MTKDP@VBiR;#qY!y>DQVP6OQo$WkiTOg{Lr{jq=(J zF>A6DVz{T%y`PKLS>hJ=Yks?eq1DF-2Wwb8nIu2@RJzgjsqs4PG_rL6xn*gg&teCK z`Jl;dOAq_}l`)RI0pO6}i=6xko@J8Y%kM6kzl1Y(YDf;kd!9H{SMRA@1{*oFhYJOg$)1unMwv zl@mz&^IbB`Y<~3cG0PI`NPQV49Dj9&kn)Pz`uaq9hja$XJ{v$k|mK$Dvc;OdRdK>rcc#G+usbUL{%sy=Al|VQ}2E7 zt_MVZ3`N8cE6|1W3BEwWc}p}RobbIf3Jj6$ow@_qw1T5AiZGQvc2Pt#zgf_nF!2{J zigzG$B_W}l3NPz|hB;uN3zm^NTEu?pc}Z`{ad#%cR)~ZPdk+XCkR3##=#Kvq(aHx4 znpiVsJTWYv(+4$J z^{fX9I4?N_ThwYDShwBG!S(mwB_2pN4YWlt8#In2=Tpl`Ip}jzOP!XRHAsBg*M z^)g76`mGXH3O(Au&Gou^8#8wZk$qfc%}abW`Z(cF{dc*-;?#}!=Nj_T*S<{Imn75n z7drQ#@P)6vVSEgogYZO|iZH;5@!c9QZ_0g;?s{jVR{87uFsPRtK*OWf!z4G=EAGtV}DKy8ALKHy}b(F zfvKPBUJZ)9h6qWSM~-KPJXS)6QQ#aXl=Xhw+?aHE*<=R0ekm4G8YGxjVT{%!Oxomo zo`fEPV(eP}3+WFa>d)iBh!vS?qYWXf3>X-dS0Pc}jFC`KCyh;`LFm!A_SXd=R}Jss zp`be*BuCogHvPDqOXaddC)<_*y`za2y+mVqD6-{n@=fk(E_s8Rl+<()(zt0g1 zLwL8g*-n--wUf8Gv0-vjNf>-kpuBllCE%mwc#XaqHq7eG_{;+XqSc&J)mM34A=@Vu zjycT)gK4t?t^M?|k@SrW@XCKjICQQ0dgB3ay=*}gc>8P~QItL)yMQ@`4SoDojC<@C zd%0)s9pyyisE_o1?P*Jx-Z{wA^*vUS;gdy`UY8 zWN5?Edi<%J4G2D2I0Zfb^crBVKvld$`-#%8$R+foVVqG{D$BHX%+|HJYx;hb8<+hiCt^JEagpC z=wJ6hD#Z%zH6#{ui?F=hFcnSGThV@lrDE9YRcTb$TNI#yBbBJcF>5sNV3MeU9fpQ7 za%RseRAOD3hd$8^4!(2j5xY=C%Eg86I#o5DCuH18WBDGU8;p#h;x}k0wM|}gCG|D0 zZ{^D$l&gU+*&`+7+2MpD z3?p~?lN`Y)(x}LD-*8P~sp+*<5fZe~s#NMLiPrmylyI#kGa~M>R{TWWdIF3r8et|-lF@?@YP>bMi)yz&%5ev?ctTBMffnBozoX2l}H z3Bw>DXNPP+34LnVQ7un+ra^bBYYVk0*-eY_j7M7dQEGivYsFw|c<)=IapQydjc5)? zM0an(^&|SB75>P_8Ds_QK?gn54i1MQuC*PVrN^k7n!&Gv<>>$OS|lrPURM8V2GDA;CcJs~WO9Hc=Pr zM0lg~gOJf-FuwcZTi&~c4E40_@^+u@Zf}3p@dNA(m>S^XMvLi-2Nu}lIZ~#b7C;4l}&Xfe7}Vjb{prT_%sUcyeNhXO0))3u9rzG_0p!<@NG^3D87WIpm*!1g=$Y?|E}Be(ujs>pGI9|E*4?@iaK z^ORR4w?~O!4I*TP}2pC0o=m;yc(Qy3f6o)(=S8lC8WzA=mv5`vxl& zWMmRE*t@(-xk|U>doT>P(Wh6`6B#tc5qzyYgBa_E7Z#ihe*P4&{TeWURj1~V3`VV| zY(6KGDDd-NpSLvnV=m|Y-B|qpm_23wwYeoKyH3iY7`$0qSy?)4(`wlH4aed&nZ**& z$!Jm)LLjieK{v?|l$WwtiYXb-gSAC)d>-oVAaPCIYgCI4%j5VszC~k$e0O)GwZe>X zMvNVMoLpyba<@C#d->na)d3b?1q7zF5r8ZQ+fSocbHrRewJeI1Txmf-jnr@0u-Ua( zTNk)yzybs+q<%FDV)>>oa|tpIR*%&8+lLj*+#w1F6^z$YB4q1xkRxQ)uv*^WB#@k| z}| zy7=|Jjn0s$nfp$mcO1J)5vH6X(LnFd;=xz23v7FG%}E-{G>9b}vj5yWGpfBiKr&pX zj-~3RJ31>RW4JM5kzEk`(6QLD=UHV&Vrn1jW$MA!m^Cg_DKYKj9;DnwX`ep{*W`N_ zg~Kyg6p2}PjMS==8s2}R>?tnfaTN)wZInljMnZ(wNk+)~Tr0BlYZA!^Z&LD)*Hx&1 zdyCEsz8uS<^_ELcXqMZBwljiQX}j2Pk8`iiy0g`iWUk37<*ueZn|iiV4tH9Xc8%k) zV~t)xIG|^`e+-CFzE$Xp1SkTTY=1a8M`i6oonr6v8|#Vs@v5&b_^Yo%j0Ij1dDm0ruT!pEO1x-t&-;JjoX>(l48?D^0a#**%2)v&VG(^K@~aM?to# z1hzyAET$F3*;w9EWPVvXXGd4`&JO+C{hsAzpRTYE4fPjy_?I%>ZDii9JQtU|SA25k z#!)F|-R-hmtJw;>osQ(<#A6cASM(0}fl5 zy5@VdD8Z(f*2B>I{VnuR_sUlD?o>QWuCa4b$(0MBHP1V&>rLt>e!KD{yELG45!rh1#{q+*hq@9VQVP zDov?7RDYT@Au5-3`W3X>11rcJLlA(Uc4Rc*RjwY#bqJ?~7O!V~-wDBkyUY#o z5Tkk$Ai5VoxtzOE5m)GW@6y^k`y_6(b#{x?CFyVGVHc#moTL6s;9V!q@F%?B{+Mt{msUwxEP`aoIm?u-4SA`RIf0@oDF>%!k{z`}Qwaq@PpHA|^QjUgSIS_h zS_S)53SlU>S_EY6xFEah|LkY{{FkEl$S@>Z_}5o+_#boHKZ>60zy9Agin4Z#0ti0X zb%#R^1OcIQY@w+S`y2vs0)jd;@idBr32Zo?{g7%GNSwplM84pD0l=qH2qY>`kwbPu z;jJU(QmWcJ8SIZcQ&+F6dHCc2cze12YrhFVu)OBO%zcnb4xiEnyWNXvFo2p@H46`} zdgP#zLvP37VFiSWqDSQj6nqnlBRr`L+_wXQuyC@Xx!O@A>963sn%i|fjjgt9BE|RBeXlFYyvzPWZ_kkD+O6NqdkfY-cw6=)aTE( zO@H^I!jca?H^mjX>ywfo|0xSwr|`{{F>0TXOT45rgfy|=ymM69AN84|XP&KLTqLzz zfYMt0iG>!Qi`yH5U2u6P94Fmi{h>zl9k|az8a-jBF}J4i+jw>opPA#EDB+U_E)2l? z{%V)@=&lm&R#U9Ic!}PTEEu5Fv~-Nx>GE!fZ-w@doiuCX8;oHFb$pi++zlN^cRzBx znmx;Qi-3ItMSWS@itm;i^=YDr!Mu58x!KCG#<-ralYq8zn!Y*NWc^AkjvUxZj2`<+j=Y%}-2w%~<%(K6d%NU%tdq1JK_^3)q<;q~T&( z2({m~r}}vBY2}{VcCqte1TPtgX{@0Mn;ET*=7g_5jQ(2OCNb92YB}yEDt)hb{(>i zV%1?5H?^p{yNPSZ*~6RJ&4-(*JnLwU2@Qod{G3X(ZG#AlSb$Xd&c9R&p(Fq9o3#&Y z_!_Suk0547@%5!U0!7IF2;O9WWVM{+I{hqPU%AJ)0--s3KI$wgZ=7WwQSa7Jm9tIaj5)9ayRc`bayC zqNlSj=awP|xS(>XBfPpvInt`<3ASWp6refCsvJ*v6Nl^|x5~`C{JM(1+|rDqY9ryy zNr#`7(zSN@UWx*u-kbPKamt(q<@|Uo zc@gN0U9qPFqsAWfbOws0?|n7>>@IU)>%V-WR&&FX!@q!-{YN`q{$GH&C=1#l38H+5 znrQZwfJWA|h-!;&>soSVhBJyG5kVG%XJ(#R_`_Ojx+UOByvy@AD$?VyP-gxy=*oD_ zioS>Klq_13HQiyq^|_tSx;63p?s)~#An#mUP=+WjCJv+p#aMkQ5kgT$ zj9Ca9T70)@bmi_78feHyzX{Q;S~-f>MACvGl_ofv^)AePu;d-rQTpbMIK+r}G6zV4CR3bHr2Hg7+=*7DVCndX!FDJIVEccz}?#MEP zL#udLyXhLNyW9}8&C;T%Bfp0>NH*>ff|J;iRvOM*A3E;qdVR zzI2zi)gL(4n z?eb9_z|B5O;1X!aQdEFc1)tpEH=F13W0>^j4t8ArA6LlcSQf1UbXcuzXAF@bwgP+l z@W4NO1%_YPE$on$CU%(=0}T25Aco)cmNqD%mktOe-*@|)J-ta_4kQX>Dv30`m?YET zjG`)}!s7yVVqdKm1^*0cG{l`qD z_-|5_*Oiw3j<)hb2OuD5q9TZi=7db6qKJsIfiqhN5sXRuqk#MZGh;$|CHM7z9{^UN zL{Tc~(mW1(MNRcggc&2KklMZ3e985?S>X5edxOe{egrZS3PdnhLFT=vY^ilg&urdG zsDFxXF}Ubfd3lZa6C#9{0L;<(R zT_`u#dyYRmpKTFa1{);<&W`rPx+$TJLELaiHqAELMEclCybD~6H^C4NX| zGEx=9q%BQ>RNcu4q@6-{&5?Pz`-|Z00gT~q=Q{Kc?}ug8mCtmqRl_Nc_`euf72AY< z6wIOc5^**Lsrln5_lDEfYt=7!!TyL z@&b1T3SUL7pb9_c*^;k6#Ij%MbNvSI?7&gLICn}iiSAVY^+DnQtt}sNY`;tBvYCw} zg6vLRl{`4LmelPtQ{Q(X%4^m?qi7;@Gy?9)*1|&n*L+VMWE2TrIL(N_z`(e{kVwPy zk$J*MOT(;{_tZ$d=_(9R5vlwyhbErAt~u!`8ddY3Di#fp%kfD1t_;DB z7dCWW!Y|`X*baJ6xJ^s3(70E>`;`4?2x+|>N~B_p+kAya0Ru?D(D(W{(h`S! zeeh8`DCD{=E^vFC1u%l3?4^g!pc{`e@fvI<%d#*iGzX%;DS~|B9ay)!!OE*=v>mwAY#-k0uTe zUMH*f;>S@JOCXF+zZ3*~CLFjYxtF3W8N0YyWM~hVxGSCL0V)$yOQx{v+^pWj{F^#k zhs+)Z_P)>BcF8WqZS4~M4{Q5CuWO}$0F!a@j^X%x-a(idb zYghyv?7J>5?@dAdU&W9HJONqs%8SSkej^SBA*o?}JN6<3n5f=OQZzVQzeOW@^nB<0A-kw};_cm}?pKKv2Xp4LCYdmYs=b{k(3_{qC}C{r(t>=7;EZveE@=!h zGj3@#G6E5Mu9MxlvhheLoSVf75>Z5^@*KPo;_@VzCej)GK_XE%@E6Xr%wuHOiAbZK zD5jC4nL-kc5agTL`v@dwz~qO66U$sgLhU{h~*gtko^1dH_4lc=6V0>oWX9z@u9vOSc$w1dZs3`+$fAHVB@k zk3G5OOz)95OU#eKPDGTyhNNnyn<>G2K#)*ue=Kk){@IP;AF5insTL&?4x_F4N;O{d zptP!UqmF3JS>4t%dQ_OGjmqmIjXP^Znxu?eWv4=g2Km~t1)sv3cyx4_N{W!|^pS|l z4$Phhp+f0idCh&h9#hc>r~Ydv*Z!0|rvmFhG~NJ0|ILXAHWZa)+ZKKyMvp5NmyV%Z z5$JM)0I{-wJ=J%Y5?AOBH|!2wvyYmNH~6_BL;>Vu#u)q58HbW*cHY^R#$?3!(E&-~ zy5o2WP6>gdsyy6R{=#p(g$t`in^q85O%YJ{Lc+6-jze!N>IY)M`Y0}cOWX3wT zue6F2Rpr)Lwg<9d^shF1QQ9w%vT@k2B$3(2@;@~V9=bt^u)8Q}^(t&-6dyjRp?hT;t}#@_l6)dqgAHJPwy! zdCi7g_I<;%xK?yau}RkN#Qu$b_%$&KXD%Khyb5{R1Iw%2_iL^VBye~lLQ3)+bLj0{ z{Iyj~ap}4Z*fhz-BEzmd{JqC1th>Cw*Tk1L@W)$G8jD6S8`zZ_`%#j#YIRAL`Ity~ z3yGG!J$@&lKqJ|Mzfo94B1l_P%qxpjvee+x?l1h*U4R;^nn1!vL~icYb9{lv!}H<% z)Qv~NJL3n{&f!+MWGO%5g<9$Rarv}bepd^YT=d~VDm`U;h%Bv0xN3QTFTdNM7H%$# z6*tC*ksPdwo`uuLFOKBR@khU;8TA3Ug=C$Go{7v8v+ADwpSunAkM$bD?tze2jO-b* zQBEmYiRg~nmrVsg7Jcmz?TPgaDABe3`ptchd<$NwoKhc7_1YiW4cSKgN+%A4T%Oo= zU5m2KW^Bkr4@ME+a3gb4k1=KlHWY^Xj>of8Pr3%)-P*g6i;$imSXF2@ysu@{rED%c z1jdLORb_7Vjx^YmzxQD4k0XUz*yRxasW0p=B1{CoK0ChZMcMCw{8Kn2^IVKjm?-q~ z{>`^;3A+oKVBx+us1>s_*Y~F7c*0}}L1;sr2-PMI+vZ8HA%)!q(K&;VPqMHKB>dD7 zlvSYoa>?5aSFdM}ugUtZywT7;qChBXIcEeRan_Pg$J01Y{$jJ(7J4jASS+cy{D6IFi-8~3@cslyRQV0SN#HG<-7lsCyfC{k zrG*dFJ2lcKMH500GiozZhK&;(5RL>F>NCH%;yT`P!br?Q%mNUOgb^}oodc0jvQ@r7 ziyEG~vI004pih%u;|o~uQirG>a`)hM?PL|@KB}R$(^ji_@0j^Q=_B*pNa_`@Qb6M} zHc56CAh2j0yF#ZjHUT>IpyeLq>|1B!&Cg6*VD<49T4x{0QA8Nd8(nS8)|f7&R*|?oK=uSKCA~B^f$vr)K0PfKy9SCJFb#%SQtY+Gk12X zJ$Bl$X&M=?_lG)SWNUW~_C`(i3Tr=XF*{yGPov>&c0o-t!;n&m@`&wGO+M1vc6nr3ve@HAhuMdY~@k?JdM9Kra{Y?F^ zuc)AAq2$zyVXM;rh^;zM+UBA)89v<7#s_xyc`qqIsE7(YMA!){yo*;354Dffw<)CPwI4WANeUo{iYcL zv?A49Ra|gl&^GyFM!G(NkN<@7=i-m+WQGrue-B7500dHsp~QEJ(hU0Zpl6X#U)p-; z+zXQA_nK9m;bE;G1Xdg7OzmDNm@T_xeY#4CURQO$!-v|S$TJ*Bv<&Ip?pLYY;aw-- z#2r=>jzt_Bs6EuO=ij%t>uwP1{D9zT?pDTW(o{@m*9quTvC; zo!`Tm9!4lK2|Ng)$BQ!?X$(0wel(qUhf~)|chvIQ-3p=|PVkKXemR_pvCW~-`0XO1 z>T4ypwGUA_m!-ShF*&tn=wiOema4FOY7z54Qs(((4XXXu*fz&E(fi}$+oSTn3shy! zv`h`D&k;vq&)xe~&q*hPQ6x4wI85XJb4q%OHVI-&rc?HwS2yQpAK4>($n zls3vu3jK=ohhiqnY$}|g55i$ErF9Zr-c0gxWZc7;b#c>2n$_$P&(#D(VGX=%Ic zAzX$yRJ#Jy(Z+%>oHoNsZjNREqLweaCzMnZ4~M}f^uUku$akNn3T$}RE(_jVGSfJL zw^EP2En+(`A6n!e)Q-*J@5w&O4XVpSGX|cEm+odJ3QMUI85FljORDuJ)p?XS(ktKe zyz9f_-{f7VMewg+XlQ*W2DcYXT%0_#zjcPf-=}kU@6If@+)LdHEYm5mBe#yPX0%lv zr$<|1A0z%s>hIHkS7~UrZDOu z^F3J#zHoAOri`Qu*G9~G{)9)0p#<(=XPscG2sR2;q*Y{HH|!jq-J!dwZ9_th-Fu{) zI?aXY5()9o^N`4feAfJR#ufGMko7ttjRI> zK33?x0siDVpyH<_SIz829llH@*_=~}74!chOgPX(-R@5^!9KkI@{P4XJeIJ;zw{pA zJMS{d$Pnn3dkL8dbTi<{$!YrVfGlD-M+jW`I{M7etSSYJn7ATuQ7y7;V#w?3V;-!A z?^Z;Gcl`VV{UAE%i8xJW*iDdZ>-%)w=#=uK8EitLXNd=eYZ>00?+5B5aU2;Tb^r;ay~@$RN)8-LZk>1I$r_WJ4=(#HGJv zxnO((wuzW0RO`g2XxxFmKv)=lqhkT5P~7=A2KI2fcOj$2bP2J-Zjxre*uyI8u%~5a zflkM26({`mG0;1X$K3n=U4QO8#$%}3vqbun6Ha!63-O2?lrzY zlwi}Dgp}90ImEZ>8O;G+RX4)?MA?X5=!c=m?CjTOt08tyBR;@>B(06k=T_T+TRJqdUIU7ey0@(8&TekgZ|VTFwpFi)g> zdixld6BRQZ#$@=eiJYAs%P?)SiphhD`n@fETdHZ$SP$%RZmgGWRcV0CR#?=_RfVr7w*eC9#O$aid>Hk^$TI_P^5pT@y)S?^UBdHX{Oz z=Wqe_sYAeZ;H3epyK0EJgv^IZI=DhYB!5;oJRV;cJs=O%K8m6a4#TX8Gg(z{%_`gF zJR(e62=T%EY+p9yZGs@#?)`x{#zBjH(zjCvx#p6kejoOCD(2}U7ns}b52ny5(N!34w{pxr20Q4RAYszEjpUGIGULO7)_1y z8U(dk6#9laxame8fRGM2J-QDJJjPvYa*`r)l8&#B3I$S(QrHWJTR$YjXtN#{k0 z1(zgRt*GUoBC80r!uqaOZEf!Hqikuy zD+MJL5+Yx7j`up8kwnAxY|nCjS49F`iDf_+D^iGH4<>z-xi0 z(!XP&#VFj0%-o)g%1;Qe)@2HXg6^e5nAl^mC1_4JI6|9_qnXg0rvx{?Z}8kVq= z$j#uD{C6>EW>N?(LC!cP-8y!%9#x2@V$-$K1P+@RrLv*bz%|(7Oh?6hDyCRL%s@=? zMZpU6E-I&^W~X7{Us8aM~`IfxoDtv`Bh`FWW z6~c?kG%~UVYIO){P7LSE2h^#J3FS(yHP-64&95laNQfY@t@pVzs776|5Jy@byE)a0q0>fAQ;ugQ*qszG>PlP_44 z&O#8I0kqp`Yr1gUtd;USCNkYis&dxGi$66CHv9?a$DZr4k2CzV`<@Xke&eeS7r6#+l}Ruj)tV zTVsGTJ~V_dAwR+Tb=-XMfF?uwEk`x6@nduTK1sm+r zx4=qx_tz=#rz6-3Qoh*$$}eSkh+kkxzeEkR;vVCxjpzC6Gu&{6E=vAT%I8Z`XU`#D zr-`@DEj7o}Lj#Z9g{vuA6`)Nh(b#ZsPsP*!#+=%$q^9&Ojc}>JTDO;PgE}aHvfDw0 zM8BYWpxlr?1qE~Xff}3rXlfGen}4B-wTDJ8B(la4AS~We_16$%vj(mFK!4$c9xN;b zc!*^O?c@oR%C+AJ-=nxm;@^n*9q7QyxQW z&C-|(_a1MWBckwyEZ6JB(kAuMh)vHqt3FMfdG{Def2;dh@pD(4)i=|fFlH+xSj=m> z;q=#Zd9nkem!b=sz7UhHX9b`wg?WbIx=TF?Gw1>^rJP#E;|P44kWFfHjGc`8Nwk$% z&quF!_r?9*3!$gom=x%fz8PQCe*<_h( zNQPS!6gonqWxSu{F_D)@XJEW95W9bz7s5g->@-uYrt7+tjgB~sJ}i9q9n++P5k(tm zONXRJ>p;USmN{xBTSj{ipoX~}-)?ZC;DJ|kVOEsvOmFBecuWApmqbEEh6CMwG{KPy z$14{X0|Mwh=PDP<2YI9f>@&-YFUw7@CXMX*>Fq(2j?W}lX#5+)JxySo1f$PY;k|%% zD?{xeHo&9Y2Vvq-l1C`N$RUaOvclaYvkhU6_}fkO&)JT@6bS8~j;ZpWI=H~UE?NBP zplDlRrDIUQMZ+}XGDDM)HE1fEH9@vX{=L2-+C17L z<8Eqjn-}Y*pcFfvFYIR3=DRa=xHGdL_}0N5<5S#wc`0yognEUuK_*YdB10jOmO8yp zli%ILmgu#^w$i&U2J3BYiX=xLyAVEwoqg@O-^_*92`RtK_NRQ6m+ehxpHEB^$J7d(B0L8zYD>3HQhBeNqwn_6b+81 zV|^d&!IvEz^7@@RfzM8Yhm;BiO*^5I6OMv~yKfA%G972^bZa0?l znfONTeyKyPIu*MU&ATgPADkkRnNUQjDva&I?2C<~jU{AFdkS^P4r2!EYMW`r$;7ss z#XIA2*z>=pk)W9~Pk|@ZX-$1+l#~}fD;wDxYgGZ?XCzCr%; zx{|_#Fim-~T?zkcyZ-2_WvFyOCTk9=N($XiYP5;EC7MF+fT>C%A-H**`MijC!I6Dp z$Li>N4h|vZ?_hWcb49;PpbK3=-l?tI53>w?P3QgfqvPQ&z#p;+AnUw-W(7`RkbiP@ z!jpkyrFKKJvQ^Aw%P+5Gijiz%<7ya}H^_lmjQQp9Csao0aQ(Ea!(OfyIvtKPe0?vX zldSpj1X0<04$R=DO_4p}>)GI6pTZqT^oG?P4!o^RQY+55E9LwSHabebgx)B%^}`)$ zwtmj1=bl;SV!aS*(NJ*IL)A4sI_p}EMMgemRz;f?yaVqUla4rvEK9^jF&`zhx4-Ez z5?x$9hWyRXw{4G2i{0R?mwWlwRF~sC5c$uR3`+m{y8qw((*wDG7V3siZ+kRhuNDiN zxoLIzF&uRC`X!v`$WIOA0r}cMbxZ}ta#s6PWTup*FRk3GAIU|o*F&f@F_c!9RwQHH zya;XWNwT?;Xb_I$t77~oM8k$*RtiN@b(yV(X%dKei9& z9PEF{@aYhCkmyY_ZkCHqU~s&Sekus}TQ*A3^NI|qQ!#~w42MVab+0!(LHEJx8h6n$ zx94|ex0O1d>khVsMOS<1Yc`z3d>e=GsLSqFEvzak&!%sQ1ez=E4vvSJk6d3!`w)N# zDb_Q%!wmyyC2mVsRk@A47nU*Ws!Q|L9?KpBs52iv+oiEGtKn6o6F&^@IS-95i;rrN zO{9u7zP*yV!NbOjiSpH;!t^3?F{@N}kD!QRE7*D?Yh9E!o=@`GW*#1cHtooCd-i9i zb4cM;1`$1;X|SxD$jNVXtZT;24&H>@NP9H(J9^?s=|$=wG{>=Hur;?sSXY37{NZlG)64Jd4EczPwTOxg-jUzlB_-xY zjJMAj^R5_sl|Ir0r{{_9Y<$-SucE?lmjP1|B9a>GKK@JlpT+Sro%3n9{<{|JPnT1m zdIi$uDu60>n5JlbAHBRLlp6HoZ0hC8cx=lu9qjL8a(We1nQZcPY{tl%<_t}>fQjX1 z*iHcm2}WPfDeBOLys_`-0-(?@(z!!nnBO>~a-Owuwp&@IT%KK`l7bs_NkO*?w3q_u zi?K1k06gn4`%boPX>I!uQCo{hIJGb-5%g9kCK)lHzZz=e=|*R$`Du|KmQQ}3WGwJl zmebK|G&TPS4SDO3pEMxW4GzdW*p*HHVzHisjF<<^$hXe>L8MCvtvIm7Rc1>QKk9%wh+kX8s_U$WtEa!;h;BOwFqnicwNYoyq*^zQkXHX$ z_^jKLs6N9mth#>ojCAVjZ->eg9iUwWEwSiVk^ypm&VxQ)y(K&;9wF z94&F|bXjXQK-v!hlOF;T%JrAUkBB!p+2Y}83asO)quW-O=cJdL+C#p!#C6ZTLH)Kw zqU?AF7^X?xB6AZUf>B(z~#|!&}{7_vSF$50CLNp_SXm$v>T;mBzKl^<(0ABgQgCC94wW zaC>K{fm~Ze?<@J%`;*>T0&D$I&J~lA%6`;(zK=r1SS(b_ckqAAJeo;B)%lZ&s{Kpg z1rC7)_V>m!&v%CTv+>N!<3G2dQB`=^-1E&j{%j}n_u=#O=l^Z)#pW`gZ9Ffa_eTf) z_aXIk0ic_DfYQ&aslBAPaKXSp=O&=^^Ez5DX&eGDFi?*Tlzv_}=_Rd41O^5=`3I$+ z*FAYj7n6X2fqM0z^z&jOFKHS|Ffh@r+nV4&$&p!D-xfR{8C4;UC|eh(=9TsQubh7x!hYyWZO&qc*AX&fOiFi@pA=((S3 zMqkprB2Rjg|2X$^9pOtlMeHfS^&j+e{nSgk0{{jFsyqb!<pa<}e+C^vPyakj^0I+7-MA5|I$_@nmk##e|Sis{PU^XOMcY!4-e`gfb!2@<1cxM*H501=Vr)QQXq^D;l#%361X=JAvB$uRW#3$)SC6=7v?O~`SWoYT?Di4qLk3jy50}i_X z>M7V?2aN1&{>90E*Ma*F9Sb8nTWdQz`~OxM<=>T^jO-ju{>23H-=c-{e>O33H?Xm{ z{@+bi8x#uWae;u=MS*~5|9ev*c~NCY69Xp~M-O@^7OH(vnmv{iGSiLP;6Urt_d+E@*B`PonXKKin6Oo%MZITQGvvvt2ep6$wgj!&|j4j%(CBWVtao<2W_@zT~lF4un z1{q`ydI@FEanUGoS%mg0Pk%UX6AbTxGIN?E->Hx@>5&2LP{G_JZg-TtQCMt~OnH^G ziDte?Jj`%^M*(^Jh5yt~9R8*bLOA<0c>5F1O0eV+1@xg#rFJ*sl8d}AcZxgvrdjZn z)aabUx)S!PWUxN-aX1S{j&>Kr{KvwAzvw{*eL*-A_oJHSJYjBXev^2rh8+C$fgJoT zN^omW@eBDo>(Q3xXyXmu;88Xy@{NYuPbGfKL~*p=>9+*;jur^!0QU|>4~gSpc{Lu& z{0&Ei@UO5pq9n-@v)e9iKOI+tnn{p{a46KgwC&%;9?F>`!TuvIU#{VKvu`}iPdZ^= z_TfDg)L-2!NURltyZjXo2rgd=;d#j1-&?^JpJmfO;U5-0lNi5~^XA^n47%g^@ zAzgASA7(-Z^nQeX&%b#jk>4}8e5Fj|7@zmJd^HD|womuWz5OP>*g5<3dh<~@NjrQ& z;Qm%P`JQ`|rbg$N*Gnt=*YAE2_*9W9TF7 zuj4Tm{VmTm8!f}wnmjnaIc&_Y!;#ydCuL>Z?Hdi}Anl!|QPSM%mWH-!pyLgE?eVlIN!EJCilnvljZ?t#S zfKCp%4s&Pzc4lW~Yvvf~)fTa8;mMI$WP5xxMqZ;eR$)(579suyUST_@F`!0BmfT1nT#3luGaS` z^z7RGr#yv;wH${Ho7kPCWB1n6Br-bbwApfEqJ~C3G?(sW zwJbIt_!VbU-}JV$ClJWPQtqYlte|oKtM9fZ-$ju1-mbcC^Ef|u08o0vR#^Mvgf?^V9^L(wn zv)bm^jBxKv@eWOn8h2a5i_doe)oAOHz_Y|*YROExm!uJxqa&1oiefZ@Ium*fx)mWX z7iOII>VKqfayxm=r?nr{@{_XGNnX20QF1x)HwbgG)bok~MXa7Y=SwNbcJj10Y3y+s zkNk*fZ}>hx6QUR=q5z4YGdC^jK=$$w2X2<}bK~kV|3WLulN|Vyc`sxtEm#xwMfwy%vRf{F z=7>Lcu*q7sHuj_-g_nno%^1|U$>!9pp%5yU<4G6`=Sq=ZUm)g4P{~kR5%_7{^+&7d zk7s;im)k_aQ`H>Y#|nP3M9ObP-zhK*D5Bi9tqcg=EMe|6&Q zNhCtyR<|_N;O4;%J~80z&UC@3ay0<>=Nhnz zyTx;xQqAbi3o9RIn#fM`AnL}VtvhAqMT`_|e(wBnMTzM*`Tg~v;_(u^%1r+KV-rP5p z@hxMs>{c~IHc6nhpbehY^+=JTDSDiwXIxDcp&Mt(~)pYvl&3wfzuBrMLQLR1RCg^Ba<0UEl#!o+g*ZWW&A@~AYez_cS3P-!Q*O#Ot8MG}A1D!a$$Q5h!@x~}>rk2pgD2-5{>hJj7mGka;s z+wcz343Ktmkp#{8V9|5X86e;_7i`*f#EB=dZEKo`$$pC9q5AN}&^|!!Q6Hu?k|5+d zl|YgnudLm7BDjY;ud_wi){nc10{Uc-&6u#=k3%xId=RZ5rbs-yS%ITQG{a)b9rc|r z_EoZ+Gifz#6m`8pY|g-Zm@eLUH}%~twkWXSxwd3ag~zA*;L&uLf8%tmfc^tniDz4A z$9*t@Y-8C^bu#j1ZkScNKk_J^M=ZyZD^p6Wps8FdfVqaZ4I0}>?q{-4+TB^p9`QtchZFC|HU)Q6sQL5n@1awEUM{hSucM5_XR#MiZ zd35>G4c@VCih$^}$)lgalUmF(o&_0den-3I!4=$`?V>Sbrak#3v_P zNInklDc)1wk{e3+YU>`RjefGzW39Y!R`N55B9)2h3GEy)iFKGpylC?$PmLLw#_^VF0SwG^bi*J`P>X9wX!%Z8nf!f;q2| zMnbCw;Cr1v!0yy??n9?(IjE0#CyuRAcu+s0eNCdE{?3OHO#$bb@Hx1Jilt@(@_sb- zI-KITP@aRKk^ABND2qA6Ex=7n@R8l;t;Y;Qz<6>ZhGECuIKiPXc0Zo0vlf-**oar3v+W|A1GN9oeJyC9&l2ay6i|J4T^Qi^1Rm=&K;PMjxf!9< zOsM|+{HZ*1J|l>z1_w>tio46~#|v2zS;)L@Knm(D6@w>E=#w)5DRnDvl)fH5HY;lw zKY8VuLyv2N@Q@o->KIucIb^8i^n#_dw3Tdys`c_--rr4i0nY0Ba}wt}FMhj0yia`e)Fc4{PC}eR8b9moM8l z&@jTh(Dkbo=1*xow~?LR*Mz`34!#3BgHQ9m*M`8m1MmYojOaW{OusVyPo0@pFHFCm zcG_WI2&WQ{e&HDiib!K8&rVg>B(;^@X@E+y7sWXwXw(?_TS_!5M61z-6$+)XA1Re{ zI?#u4v(p8L>outPHp+q+id@a04$Te(_~$Alu+l1f{|3JT@I3EJ_5;wnR}5(q$nOsscjUX4y7m<})+SK}mXn;a~7SFACdmdq9i> z#K^UNb+LfKNW}`U`G&g%eUeU<@!>Dg+9NUKpP(8Bl`hQ8E#M;OD(U;)rN+mDyt0a~ zejH2azcYB^Lk0)SwA4?Ctk%z*gDe2z@q+W~@|oM`NlqOxG`PC_(@&t^!9PEd{e}*G zOJ@JPxSvknioM|Hdoj%FIC-A>!U1cYvTvMHSL%x?gf9{7gi(egYReMb?N-^}sYEvy zd3*O1?5soU#3rOS?MP&62(w**j zdP;X5jtp+zrMF%!roRrfN>4tR?b|XsAiTfi;-mOI8X0c8OY^#0N`KD$mA#nlD=^++ zzQ^VLmE9W|e*KksSW0*D(xbq9X1qeBzf!%=WdD^t8yWVwOLyA;wKLHsM}KFzBTjdR z`t$RztnQVm!Je1=%k!_y<*)3G#X&o~$Z=CqHY%d$jj6#Lm%R0GF}*cHw>e;W?N^Y> zOT6ljnoUqTPJTd^PXQX5V3srWEbH5@xsVseeYm*2>k|_9LN%>m7mHw&8?I<-ji_Nw z>R|gJJ$N0ii7*=bw|E5S59=nvdrFx@F5`PF)~J*Ah-G1>2Lw+UD#Mnl@U_QwNvZEB z-*5nokTRMp;J$r+5J$eGcgg`lSeZnv-HW)onfHfJ~y*FmCSw^w|;s#66k1A;cR$mHH0 zMSk*rSf`4iaMNC0*vT&CkaanA0Zw(NaKV6qR%)s)#Gn4JWod0fUs%0>96 zq>YF&AB^A@Hk3GMaH9u~g3oHyV}HIN_M8z9Xu>UHGt4!fyg&VhQDH#rfU<%fHWgp! zNA!WKTOsau$c1Z+W67}#>OMK9ILp$Vr)D3H1?2BpLc2n@2h(?;-}4l0G1rGMXONq+ zGxs8oFxUAf9z0#6Jjoz+{)~CQbpXnP=au(l?3X+XQre-r#TB~Xqg0ArP^aL^cEr!% zDl@^JQAla{g0FvLqABolZ~W-IF0gWk`Y72uqL~|sVqgMMRqj5o=^NA%VxIA2Mn@n9 zrGs5aMYN8vK&j^U+;MR}bOmooDJuw(^+M=8(QU-OHST;?(lGB&#j%dYA7JO?F<#n`>(ZbR6BYAgQWC z)j~|nw7FU^`yP0O8sENVANXiF^IRlKz&&x32ig8|~__imLBM`Ci9H;e5PtCB>u;Iyy7cDe&)iKCp3e46oLh;-RYG z`UL;Qql@}n_-4=l*p>ces=3}#R_T_ zwk6C5UP#*N_)o&?6-}FEPWaXm&qb__)ZNnSVjapBe))s30cNCVu-!%K(=kFKGTz6CQINhPe~BEoy4(FuaGwNEI{`DQ?9U6G78pUr^~Aj(eo*GKdS zD*P%hB-O-&JAZ4YxKHP=jDG7&z4FaUbVT%u&bH9$6P6*=)_K(k7sm#=8jWH+v2Lo= z)iIUraH<>m%+CR4EeX0v$9UdK7b&vel=qd@B5GvTJ@MgeORE++ZK??r?Nl_1ZygYR zR!fR_mgo}#dJy^&@LqiVR#|AR8I@MUr8~=&*m13U6Fy-T_yG-_{D@GfOM}D#{$_lk z>YX?S8%hOPW8%98?b^^Q3VJ%E4Y@u3f#*^3(*~%ddVz#?VUE}N~k$iJiAo~T2uvQlI3@q!%W8_h7yUJY-PO(R*E=X z91SsK!h&xEWINN)?-2n0>;*^Dc~&RoB^eWH2X>@3z!aV*5%Qoms0Fn-RMM}s*!^$bvWx4q?-9u$6rw^P=JN{O=Wyz{Y*u- zCQtz555!4MXMIj&T+j~(pJ}(x`GZA)y?zf~x+e+r=*3qj<(Hlp)g?1Y^h3UrhJ_9x2;Z}1ZJF6e3(vEhDaKvzz(%cilz9o5lVe$+haMUXsU90 z^FzNG>k#XNfY*-UFkL;`z?Mv6DrpfGl8{=zQU)GlJ-gN)!hJ#K^K5n5q}31>c&6Mc z+E1k?JGG`d2Rwg&);* z!=^K9eyU~|?u=hi&4sgcOlg7zHv};D%1Kn2P!2u648F*&D|`BNo>l&9tcj2J}FwiC!BG6NoC=)HG&zf!(Okd8OCRT;d=Iy|+Z)3agd*OXbo-_{CY z<_pvk{@IMIq9gzwQT0w*6K!g~9afW(3yo}k3C$L&Re>h6Ovx5YCk=?mmE*|m7am)q zmTvLlzpTjGb#){Vv41exo+~sQ8+tq(iU9Yk4>vE$uQHrRQqHH0u;G zTy&Um<~RFN3=uE1qF8`TIKL^~Iu1j`zb<8&Ldg0MJ0)>jFnuUGZbW)t-2x1Kwm$MZ zaGV`CyWYS)B$>9IPqEcCd4+m(ZDpDHj$hNU+SPkKObNN#1$Y!~X&L*jOIPXkenxM> zY?ZvCeyO3P7g)CLOD3;b=|@;u5V6VQvCY3N3SX3CiFW6@&O-F(U|nwt3IQUvC2Agh zt5Nq<>E6z+)=fx%6D-p&wF6`~0d?{MBZDzJ=O&NW~l zpmR_lAjbd6ABeb`*g9L=nK}Klz*?d(VT;0q$~WC4Be;&b4st|9ie5ly8lnzHr1GO! z5>yz@Sc}Ujsr`PHB#weQZwNX9oS;{XsMf4daZz04y#M+2b^D?9;o>DO4@h_40McdC z>cAHV0aLRsS>cOK$mi8~eAeA4#CSD4C4nH)nS6_ae<9dVA+LYm6n=R8urWjXQ3ezW8o^`T=P`|I*sjsg`1hR%KhN@75ht%?47C zGvlP_HJQP^xGh5rYoraKZ0mG`XRh)jJ}<;Gyf0LN&VWpyF{J zsc&1spi}awK%-n+p&C>OY?H>S{~|FrFGwYM6{5X`n8i$S(V{*&P)0&SI+B!#LJzv8 zhxt-*)x+MEl;z?xWVEZnc|39^W4G_-+1}-FdJvsH;YJzL{o6ZsM#upHjuq?q+wYS# zu!ow!tc>~2Js4XMBp(VL)530!t}qGQ`I~2zA0g0c;S$*^d5u=sDtSas6zHa1^ClhE^Vh%O%pE;OP89+O2m&4mh~<9*69Gp@0}o+A zm4ATlpGe6`(^5lGLml}Jlg8}*0SzWHs3-tOl>>a?LC6`zyz1n%39rV}aV= z=(QAHH`=BjarkIU7>}H(x@Nf&y z17pQtxc~~~-au9N_*^~?3hx1A=}&}nf5Z=WkgX(;^>{Q6aO}befCp1nCexLJ5xInv z(PAXln8bkW=t;JM(=iHGfIX{eNqVh@}^Twoc(&U2Tq_GFn z%#a?l*Y~TvUa$r)F4bKqHhUbG=;d{JLwTSxScT`J^Ks3q$pE`zsnNQz7Efxr6prk& z>H6N+UeeJ%amnT8nmZL)YTBH-upcQN2f+{LRJuNK@cr%J3%*Bw#c|}L5I`CXmz7q9 zc9T6Fh{Ep-M|4xexJYpN(u5ZaN(Z7<>tVnGDd*L*pjm_1H}{rNY>xO06`f8AHci`^ ze$*9=HDQ6``uQ?P&7dp=E(@E@;DI#(y|tQ!4H|dulplDu7c9sKM}OtLvWt=Ga%_efildl~ zj-UT!+7~~-Fbn~v^+E`l3eSRomevs^#q?nh- zM!~zb*m4-z=F1*%Y7}$Fx{rH!GD4mN5yBmpR$X`@g5ItaL3jTONY{;vF!UmZ8wt;L z1H=}}IKgSHyQoUmOJivC6C^c?PMsguK=Z*}Av&`u9kX4%;Ho%ylI0b(m8!m6eqcOw z8AJ~q$<6Meo9(s7s3gxZs8~*wROwan>5NN6_Citn4#8+1#n6#gYx63bZIEb;v_)Yj zZ-)7tVG%1N^~u<%h9(G_KDsER_8X|+cQb^9Y1h$X4 zn%a@S&a1x>9rrB}FS9!AEcL<^gql1V<9UR8tfem<;2mr)UXN$>frK}%fd+8Cvak7B zp2mI!&)|DQW3G8fWl3PMf40-}+i&76FHEpXQ#*R>g5frIQ7~6E=3DJ-qq0lz$!WTn z$_0t_wjG=syP_=O=allv2tQz#v1N}kicjDINClqBFnzp8nJ++gvkzZo$wTzU=+kz+ zv-%FP-Mwtg^0Yy%AhSfwf9WD!lq1ksDN5^9ApA*ApT^T-p*}Ac573&hCwM3pG71{a zD{ch}_CNw9e98cXkKXCD4=l;?(sC zc&yDI3JUC4U-om)P0`0Ofzc*ykpk$LR;Y#BM#peW2a?}HeH*q$Qt`*^ar@n`f<#Z> zOl1k5_qR**UTu|7WY+KiCY-pZfL9zsD2XUq(asKRKp^%uS4}{^Nj(k?W8h z_=T7qgU7=eD*OqI792=J^@}y3oR$)~JLlbh>fNVOq;*o96jugk#2EMk%S* za^PpUYHcl(ZZeE9j;+Ui<5tPuZ8+qmbBSBk(on1V0GIXh9uQCKt%c>=qT}nGc+>JO zRQ7|3RQtOrlJQD${On$)>sX5&u9h)=rJYEl0wp@QA{TUELvB_e7TB<_90N2OY#|BQ zO#J<|)vZMAU&AEr-qK0@0|;mw>3MIKzJp_UQ~7{kbAy6+-|nF_<-i&IP~23kaFlkL#c$+UX(srxTIHRn}q;D+Z!p* zH;MBuik^9&?%#wy`th|GtlH(rGF{m#&5`*VhjQyx&&mt%X=SBbWLq#fWMwYuv)6&# zb}2L^8gy2gCN+g=j)B4S=A;*1SF_LkTpe=`Ek-540+IqbbSlnH!0c@S54Oif0=V@=oOs|mchhRDm=}j zKro{k^V7ccifjP_6gCTu<=pI=a|l1|M7AckCfzYDiB_dKw2$zttP-7;=~=6)^k5t` z_K55Rna~stI>$FA@2QBp%7ZFus~`aeD>j4v5v$VDL#SXLBA}=WZ3*PqhxxvI>a3*F zzy|Y8d1jHaN+g6ohV)2f;Ih3(K%QKyMj2pO=nVlOV#D7zWB4ahRUQeQS^s?g>;&wp zBGsv~f-LH6D4V@*_5>WRye&{yI9~4;zgGuuEuFf@79-j_aU!HoX(5*O7jkOMR5P@x zpT_K5v?K^<9~8PYPK8sg+fJAJ-w7#&u3x6Vp?x5MDROM+ zlM{Mx3a2XyvpmFi20}Teq(i&ou!nI(cd=F91u}uDMxFmKRwh1{9U)f{2t+xpEcix; z70sWGZ_kS@qG3f1MebiTvjeBP4D zAB6sctaa*WeOt9^f+|s~88KZT*pnI}Ehvlfku~V1%TP$-N0X&fWjxn-9v!NrLwUk> zsa3GE_hqPD2Gicw{G&%~gXr;euyOefG;;V*m(nlTXWqYUtiT#>qeoR{L z2X#K+p@R1QJO9ht`j#MkK1YzFi1!{ksyuY_kDtlINCRc-(EP8?cH&^%^iZv?@^G8` zR^uj3EYJ<`oY0^;j7o5t?gNc3Md1^OjBR7WG*p1j%>J?i*S_XsCB(Qp_$Iys9|tc+ z5G4FG(PXurn?21`N3PN(D@IPL1p_;-$H=pltI@P=TVjWyUh8EGINs#S=W(*uLs#ex zq|#O9j$>&yTL%_vc7^OI`??a_o4LioSrKjpTRROrj>YQ*8VEQtaw}yf?k^smi!9G{=efnBsS4&5q>0;%^S46DZ??SY_P3Ws$=s##9QpHd-=5GNzEjTt&S+S!! z9j*hK*00TI#jDW7b*fuXHek`H&fqh){l2{BTvfF@7FsxmgXMUu_=>Cb8wUFh#mg4W zxC}=IGa6C`fFo9$;9WY60vf!lGcXq(XXKk&HMiwic-O8o&mX34b{I6%?MwC>;+vR* zC8-O?>+;s807eVL1|>a5!3lW6+VQpq8S+P=wg+=mjV7ytj`K%ka0|9^{WO){qfbv+ryc_iAlw)k{sNawHgzy zURa^F_Jvzr_}9bX=Y;+AgF+pNK1)0`<##4niTU%B!_)S^)Qmy7IdgQ)8Mx48ab(fi zgFk#bnpT|$Y9erj?B^WTw0 zLhOJft1TDlT5}ABIAV9!g$q%2U(?|%INJ@{1Zj75q+{WVU4X+Xzas=`yLPI2JdgFN zL=@z9Pkfd1TUq<6C;|%vai`PkX3|OE?SCh5s}X$z(am$<<&VIW3$l}R*VX%C>P>L#gSCU;?Kf-| zM9}*hunWn=56j>GihJ7@Jp=kPy#YGcG#mT`(`vUU+N^g3^I}(Hc%;u`7~DR=0ZQBS z6VX1T0hk?2t3??XQNV_e0mH6W*8gV8owb;?-eygvA%+H6l6>%$NBf zsuzRB7y7j#IuF8^`@qaUZ|qfL*Nnv%{FV}&Z zzuwrZ%B~uVFWhT$v>v1{-vNjJ&gd)hZ5Cz^mbb-Ax3k8}ha>wJ`Yl@YPNW{u4(i<- zJf#xpPF}?OOnc~HO2Qb=(KjQpga3BOjI{MHwRx3S)l+3|5A5aplSzklSGuR1!Y>Ex z-XWDmKQ^i|bIQ4}5;G(Z{F1ALG$Ozf>AJ*hN0G|T!_WUD8=n4F%5^|X)V+TPC9uJP zfXM!PPUdXl=>e72+vek|;s!w&VoK^` zl0b+ul@6#TK#qHu?;_#jV2%jmN`NM%D^8=}$+;A>4w`NT;!IkUH$!l+2_JXqR21+Z zpdVUt^^i!}4avqPlt!O~ZuE5du+IL3Qj*nw%oXrSxkT?FdP@- ziT_MDwbX3|hqGB$HP!P*bd^PId=`~=gjqYQZ=f`hSn`IFP7qN*_Ry; zq=Dx|p1ao;i$Ol0PVr~R19d_Qoc>gu^$uE!TQ^I67zYmvg+`sZA(9PlYvuA2*Ud$? z_J!4%nIbJUMc_SNL_3qMeA!)fxqx7lcPC7ZT)^rHM0-ZJY~4SzWK@m-B@e-BHfnsL zL8L0Bt(?5`xx6_=^%>XqSi@P@!K3=P&zL8SziVYDWUeY1N|`O?aHIP$38j+F3a3 zl8U~nJqa4wG7_2ly0ib`FFXmE7FAE2)k>r-VLC~yvS6%8`NHGMn7M!rK(lxOiViCF z2-x*5J=VtD%s9Ov`h{m}zz-~Bab|Q8f-2(4o)KF3vVPWj z7=;N*Atpq=hMQ$EpB`7@)po|&m~a}jV8If@p_r(|?X2a+&EmsSG{313f?cr)C##x$ zP*`bM%;{_{77q^}PYC<)D_nM`RYP$cB#F=z$>uo>lD=j}zU_P2jBO?%cHd}jRhB~` zta9dr_1(?vvIH?v4qXP*gIgoQbcjpDc&S7xv@q@ z{4A3hihG*&O6-j%rNr=>Y(DghNiepdP~4JEzTEnDo^0i+IAAMUen(7-pAx}kS%me& zgl<(8+)*dGuqZa1n{(NC8p6u#r?4&hdd*8nCv|d(|1!VN>dE!we&0L$MrXOIZ9)=i zFbSiNKaotD6Z~^t?HaGlbP2}3PhBsn#j|_Uzr8IrkOE`LYcPM$|6RX!HqmQ_g=rd} zt(}P;!1^maLm$13>6k+OSHdfqp&6#>NCnqq(yzo!DT9D~=?3uzVFk&U60FpbO|)v+ zaf}6ZlGkxF^)fFA9J_x-&Db}cpwr*UvZB93WB-?j*?*$u|JnS1Y@eWklZDYg_b^5M z#c%N#>wBDoH1EhI+OXFi@yE$S02E2_uW*V8lprN(ahrAS`y6X9x5NZzc6bfIkWG8y zb*OWhP5Z=;VX#JS!K~}9h3D_lva5&A`G^B=+f4#l&z%#WyeFU3%ayM`pHV=ryLwE3 zT?O#CF;29Bj=Nk->k%)s?Bf?eAUxL1!O;gA@AM4<<>|2(!QoVx<*k7?sc032`%`gX z-2K`JsyA<_r8jXXBL7&N9Mvl;i?`^o5>s_=(UP-ws7J2p^$hdMN&3+Pba(!4ROcsh zo_B`Y%;4y39p!6fblu&Q+1ud-?G29iy$tw{;;jw%j)BUK%54{R_7InEcA5iG=!w0; zFsxn|sgY_R_o7q2Uu#jv$FG@Q|KN9i3ZpeoEirbhi`XV9!PUk4_F&EL-FQ?Y zUQ8CY-}(z{ne$CsK4Q&KHFRYeMmC_eHt9wk&$EBZSyBiZ9Fdc&bD8cnrxWVCLG*N; z;s7q#MqQ;NH4b!Y6L6@*BTh=B`obi8SUF&eZy@b4(KOZTzMuwf87vQ0>Ht|M z+$~qQ3Fme=F`Th84XAm?B4RToc%K543JIM(t~+s~L1QU6Ac9&X%zWL{20F zy7K!@aPfo)7zMTX-LcJ!QcSq^&65p2>#cQd26@-`4UI3B>=I5cSx8GVVTSEHj$Zc% z^aVan;J>w~E8w_l=?oki_xB<}!57%>J?pp(I3cKR7-b?Wdb4Eza9RL2)SQ5=8Ci1e zt61wyAX6(5Q7cOHHx@?T|4JP2wS0_|T#cuV`s&o4Gq9Rp9CIIPW?R5IGO5h&V1C$> zjde3$ZC0NQPNhMtmO4>F#hSLPB`-L)r?3;Xp^;-}sc{-#!ovy;b~zFUpYvcDeII!v zBaDJQfm=Z1>Of>z4GWJGP@d2NKaPQoL$yv~?w=EV;&J)C5VTAIn~azo1Z-`WQ)ItK zsX87AwdMRlo3Ip`u_Sk@AsdKzwwW{b7J?}K6dy^7^i*B7CKfjU91T3(2OFo&if z<9o)MY*rCHL7h8-hSuT0^CWW9s3u9hp3%~p_(aY9`LS3OiZ@rR?7ZiSrgj$?Y5O?p zt}rC!t}*n-y(3cX)(2{8XkI$KJ=X=fHU)DIW?6DF3)kb?c0SC|^EK9kRstv@(nM>mUX=&QjdowfS}{aHB7*-BS=$jjYr z>HbXf2LNqvIgEw&eP+H#vzY^5DXcv~>> z<}co@q+Bo2RSGRs5^!Ja>Y2EejK5wZN6D`jWyU&AuBHqON1dK{zIY2Q%PMe>>(HsW z8|!zjm&KX|r|Gg(M69T>^klqslKnOtv6JYWx;-kXybm&K2mq_?9+~8D%0pDqvy-Fo z*D?<}Su;(DCbUna1ADJt%>9oJzl=U=$8|bTdk0{gS*blkSmg45h=;@@4uk$9Ampm3bDlKKYc$Y8ivcfh6*nSnI`^}xz9pUebPT|_3LBd<___}49X0z^C zchs}8vL#U+$7Muec_N&sdaO}HQ*ctbRM%;p(eEi+J#i{2d&tp?bQ(aWp;&yw8H-cNQ| z=!dmMO2Iou5yKk;TV7^$d`^>vX2 z;v8dq0HDQbv8Xh^ElPq+*smB1`CiC@B& zjeTNOLyeo!rAaBJ1InbvI6Mw_jkjQz%QQn$038{wICTZw&ME~PIBufh-FsBk)-e=C z4EZLEi>UaRuw{@CBr*vB8pYQXTs3EDbGlBGYw4)nL?;n&4G^Dj)3$cS6R zM!KLBsKdKwt>i5>DjOc% zT42P}24vWyu5}DrHFmO{40ASPl#Z>{Y$4_g;rH9CRz z0|4 zJrCSIqamr(B8w(#VqhC^QnIuhAf;%QV4v3AsA*PbnlX%-$y)ciSH!Q57ghbP8S4g zV#u{Iv}~-6%3{LY2WNZU>oIe+116oYn4By3#gpos8ZXHDW8E{Mg&;4k=(S-FR>OH2 zz6IHM+j0F;zc{4KqUhB?hm=5Rq7|&?&V%j446Ay6_q>5$DvjNqUMPXFhp(03o~rR` z3w2yB2tuw@s3p)TsM0ix%DN_rFp~AGUd`GTtn=O8;ZjrCc zRM|vUkY@UMEvum{i5+{VRH!(%L?p{vxO0Z_ma5r7h>*&?94E z>-=BPqip50p^V74!mt*L%uyi2Xe*_J|3o5;i0{K$EVBs-(Lv=>Hu)HJBD&1^d#PyD zQR@rFuaHGvk^eRY%NO-gdkvF=Jp^lFUFT}e$@N9j@AK`#4v2n#gE#e70v#Mw%fmZz z#!-Fn1m+b4qxmoGNNaW>iz7W>U!P_Jra|ptY5`m6*yIYF>&{)qmRER z?`9}6IQ@~Ggv@siv@emBRy?RqbI@xa^!eX;7v@Y_U==K5;A_XVn#AG?h~L) za@ycpP~v^^Jj-L>?{(j6VqAi@I!~51|HYXe3BUA9zsLkKx8$o;j&0kvx#Jz%w)w@jZQHhO+qRwTIC(i$=hmw__3pj(TAOSA8*P29 zeQS+5`xw3Vk=tp+a?RSbb|L0pLbdr=h?bl&i?0g+<8uM?9oKH>8CK2$jN+$d2$RMA z&2RF+j>l>twavQ}3jTc^1+5kXY+x)NEuF(|y&6B8+gSW6HC2Bd;JBGTo2X5{pjLh# z|4ZEYMblM!-a8L84A9<%C&Vc4D-$*6vSN?eV9ia`Nw@jx;`-$0a#2lpxJ_czKG!6g z206@+Ju)%x_PEPj@GK&fMU8G*!}u*b{SiwW9n+Kvo2KC74MAk%o+bRDsWI7y zv!%6;8&il82YgoBa_?QD(P=)pwj49(5bTi}>0PDr8D zYeyClJP7NAZt-FS?u$Thb_BICf@lXej1-49w6+|3_pq#Rzg2F!uvX>`zc-K4|3T%3iS8TvGyQYZh?S7(<3|ph zzM+&69%!awON!L0(d~tl5)-3GXRscX4U#X!VZ>qhWI_A<;hk{XButMVsx^_xVRF=N zQk1Q8jrRkSoz2#KCxYP6L55y&QvE4(x|QXy%iyum-m`c#24brtH-qsYC<9yLVF((f z9&1G&qMQYj0^!%BdT_1>)q_yfRSRJjDrHVT@XHz0pso-Lx0~6J7IzidQsX(mg9bY{ zt&xRL&?)Dz{)USv$d3qM!Kz?SYie}kGNxN~ywc}oD25oBqHf2B9vmCSH{TS8D`)`x zsAKO&9|gV|Ov3ezJa+40o*7-b=yVcj)~*ujjya#$9?N6KZ1p6j?X6B_3NzH~_D}AT z$}iebt_q&CJ~Fp%{;Y8J_r&l&A1VL@3x1TH3QzXn^GR5zwF%4P1|}*-6wDPh_-_U# zNaRS8Bt3m5QLX5V6cU#yDlhdqo!>MI@7f}35aZ6L^o+9o*F;UAvZL4YZ3@(i{(mph z{QE!kpNljq5blbL7+%*C#12T-0_Y54J?ucnsl*YGB`CykAd-Othy@_Ex5h`L7^xGH zOlo|G=JIfA%nR(Jm{2CQcq;qPK_&fzo4RnV3NZ3q3FU@BCXlc zL-du+@HLaZ3v1}9@3{-q!1?;GZ>|&%&$>Gp7z_1An#774RTo9-gnH|S8%%BlhqYOV zW#{6C$aAFB5LEej)iOmiLzp3;E%`N2pf|I*or zQ%Pfr())-(7!t^4(u-RcN7ngL7-h78~x=l?;N#te9!E{p6y1%?kQk&=EmU6t9Y?-w#D&`6H6>?PV zT@g8BFr|`Xt0lRuMol^<(+yXK*lm{uBtONCDn3VV_1rXi#0@V3Qn$>E749yjf--86 zZyS@CR4@=^jF2q$JlETo0jaHuekqhe8)Cu1cXE~M#vBGtcc4t;Afg=Zb`ln?LaI%k zjQa&cr){34nqlCqMvP4coD>>!da1`h=d&Z8q~)}SB=0M-8YhT<;)2&9vmA}p{Mm)D z&<$v6Okl5WjGn@(BYD7P*X|OYPGrF}2gPBkO}2Z)MpkAN66O6>sArL>1o;{xzmmKl ztMdu%;ILr7@vF9l#rCIwG2tS zx-}JOrR1~}wrQ?&@>=VWxtXW;GTu3U4)oR8W4#mZ&OEIlZUUGp3a|B4-&g>5_u9a0 zL`28;wQ1R9vE@V7`)=<(VbWsa!?iNyC4QX(6ib*nt4d~iz!5>WhVh^`!aG43=TZop zJZCCX$l0iF-qDd+<;>Suh*o%>PL)&3I1k#>v zMS-8dbNGCrypxXTS_1FfKH*%Q_h?_m3au9;q1f<3D5LE!t6Tbewr!JryA9ff9`Qgw zL%EnM0Fz;H!|6EA?tp=*wkjqlwHvy*OKuzDB)Q!@4D_x=@tQuBj5qq;a-%)OnpaX^=7HEr@og#GR=JC#en*a*tlgm&+)6f zr*65545MlHqF=wYw=O6M#WYgoOd^DO9e`JH4Ak7agJ2x&)+~P=24IRSN3-Zl7eO4A zG3p*cRENd2saYTv3)9rwZ0Sl@SY>4cah6|h1fg7375qJ?(Kh-SuP$&$cvLXHd!SyF zZctQU>NxE5A%{4cM-P&E*%7L4eP+Ii(UwwuSDv#g=n+GQ=0#L08gQ%FJ$pV{w^1Lu z|D)|$D(j)!{iUI$oWn?HCkECF%^HK#8)i(*6O zfa}i=|DC44^Ci~Vz4~gr)MyQJ8s$+szJn2eA&1&`DqF5A*_{|(iRl+~*{t)%crq$~ zm;6<~1lB|siD9c`uMyavsta*-bq#4>0TW`FRcaQV%KrVqH6wvz7YQVPef8kGpby^M zv&^EXoqT$J_6VTKqs@<`Ym{l;;9kg)s@q|AK^o7 z#Lp?6gqXoty3t>ikF>>ZQYwoC{M1Ijq%j z<1@5T&UF=OV_y@0$6Gi!^d6zitimE`_!)%HVhk2WyrD$6k!f|L!b8ff@2z)(G?{#% zCi4Ge!BqHrEf;~Vs!cy@tTIvzv2m2@*eY7n_9Nr>_->r~G^$+%FWazj>^qGOxYo>?0PT?)fhetNI3L2u{h&xl9gWFYXFa)8Xan35}3NK~wue9OJ0l>T}+~;<} zCZ~n-w55FsCpRX_<*BT6T81;kt;9xJ3G^^!@VJJdyaVBHdfH{t^tX6MzTC=eIAi$e#`gJ1kRv++ z-rm3XAJ53Sypt-kOa+@J;rOgC@af3(T>~xprJ8^5bR|O%;85UZFjj>#lar3lp&SgC zRc|*B#1H8xWX|HZl#r7R&FP5e+fCU6cW5!)SM4;ns+GBrS0#+9DPTs!8y?|P|B@Wd zd>b#Rj0gmW*Hu18?(D_JYP2_cM5EM6fn`Hh?gD*9xgKK0;Q8X79rG+$NXTYS70;`; z3PAvHAWUw5KL(YUE+c=+pHw6EAOxL|>tXLR-LUY27Ki7c@qymYEK>p@o=6GLpy5CN zJX@qPQDbn^K$zzFjGQf&k8}vEup@G*6RSKbU-W2N{$AWo+5UrtgnWZvGEcQvEH4P& zw2L;Axo*kTuU&U#f#6r^5{*&QcZa1Ei<6YMzJbL#*JWH^QoL)`E-+Bhl(8WAk(PYL zJv=x6iRkgKkO%Mo(r#vA_-~jeOZG*J_Z#n2e)B{q|L@`d06h%eBX{=K z>*nfK(s?v02eR7DFATs%hUy9k$ou=f=B8K%8TpisL#N{0biefC?L;$fVW7(53U3-Z zIZ0o29&a!?d%wT`#rdJ#XNM^Mhn+CSTp=4Wda?bNHp(=x4CPS*7tWyH&c%CNR4G$V z+qI%gH7WBs!}o3mgEZ1<)JDg3U6Kb}lnMz>tofouFN}Y72kUzgQ7O>4Om@?@qP}BU zNucGABqmKBLmh6^coNRyM4HNOxRj*Ggs6c&~doqF=ihyNN6VkF8{w#-S zrW9^c#M6@S%N;3q^qLJ&H?-zhb4kJ>7wvZUbN+Bw_Rp^}`9#m`o-4xrz|lXg_9MuP z@~JlF4(QUtQDBER^fWcyzwJ+ff=>lk%#p6AMTz)q+G@YL`HA?L4xy|(Z*2gTV*{-h zd1_!-XR6nEPFc~*6Zd!Q=@|fpsD$CNjg=Q>! z^uZ=E&1hrWw;YlQ?{HRWX|mZ~4(PqYuhhG;?Jn8l*7aPL-(U4?w$=ezKT&(&;l8hm z_V&T;%7GJwhic1)5WLyea1tZ?6GZRQLyrm-4+?IP-2kSztkQd!JVbMz|D|kejze!F z_APQsCHV1!?tl0e{wG8?s0!twvFQ03_1IG9aY@W7Evv1x7qyav4E!@Vg;^paV6gH} z2@a5S&XIao6WvH$>;X4=#b(ZCdA^Z>RW2O5#_*D(M(z$fGPgSGT3u|T#`5seu&M^@ zQe9)irn*SF=a)lum62MQLff{@AHa0$amJgs*VphU6Q8RkY>)CHqA=Dcyn z&G6$&6rAu487MFHJYVF_H1vC`rKivqo_SCIbBV9$8A4A!jA@_bFES%{*0D>4y1SGP zFG*=WTw%DZ5MAlNpM-v7`R`}@2p$4M#RnHUV;9wiZ)O~Cqu{(oJM#iNso!{GfUE{FRcUVkk`F8sILyo^fooa4ft+9N&Q$hufqYx4)4~-RF z`t{k{)U!Xq#{ZKyPLYCAi>M9xbVSr6()RR8;MApZ4l+jYe6t?OsYRQC!J_H#lR`|D8WDEeq5&X>WJ)OerZwSu9fs&>9{M|HU;Wc@%%Wh1pF%q5e% z3@vFAK2@-p{Ou@)T~<$(K8aG97e78$MV5R>=XA+41y`>ua+BO#DQE6Z*wdl}2&tB@ zR+5w^c><5O<&O5#E&$ zlRvTKEAJey?JJ>1oC##$@)qW0E49^)J)atkUsQ>Hfcz`aZ;)oM+meE`%$QbWrH0!W zme77BMyCSN7s0-9BS|Z*<1>MzKmyQyEz4WuAL?O4*47Ax!{e6tdDxQxjY&>5W_6^u zA1Q%e6+~x2V=>R-vSh2J5LV;Q;Tz3LM4}~E6JAK|2!f;>)LK?3pVTi<>D7|3XlQ+E zV;PjpDGARRsI?^!Iub;J{B3(E1;!%?jVQU7ah~KiT`n45B1_{Hy|$|FEuCY@zAE?D z!b7=>r5lqFaL)}Gl_6V?)n0~>N?h7(`Gte2L0m#~;K)vD9itIGG=-0rTow}AT zbxzz>)M-4YM_ih3SY9vsthz-ZE?G&XRD~q$uEJ}R$xd&dpGm8o-;9C2ZHS0Y8V36c zLCnsbX_94*odu{9CZL0m*Bfpvd|bPNay9Feu5(*Sn_xgCK?27LEW!Oyd}A7nwq?=; z1(7o}YR=H?Q1|o(eGVQa}zxa}0*IAScy%B5e;!kXH3!NqNB0r9Ja{>FR@d zZ4G$uc9#-6G)Wi?M433OF3>pfn(R%wg!dhNH1S~46(+d+S$sy%bYzpPNg+;RIua?J(PIGbzEhq(|G~HXiIWK~o zZF{bQWC8+xtsYAolSNQiEH5d=OfV}G>DW?~GEXf{Do1%ZU34YWP8pFh5gFu#CP3;A zZDum6X;Z~8VZI`q8EC)74ZNqwYp)R-dNb;_`?&+bv{*4?H^qZ)vEG_tYdMxWSi2^x>B${Z;TuXP=bkiN zD~w5vmhDY0b zUoexCQwMvll;~IBS|JRC^-g44B*v{HI3X!U8jeW4B1YAtc(d=O$F{=XuHJ(IQcerm5 zvfWe_S``%{+I3u!jad0R6SH9U@Vi^m?q4}+{h@jYJ~3T(Fh8q!A_!oE?FQoa5awX* zHoldwQ=4!^&-i}6M=15C(i1$sJ)iu}H7qG9?muc3Eozu%F+12tx1rTRuffZ}rn$2b z34ql{7KuR~bU`+2!=_gFYiajd5|7Y&=?L-{RYj3>sv{dGRrIj70`w~TST}xzQ&#ke zw9OJ8B2>`|*60<#GGM|KERL&c%-u*~TbESrl3U93YsZ!EuLyCahbpkkTwqr=T%xEC zBwqc|sUfwJD}1SiUaC1lA1Z}+EwzbN4*-*%&TAyg@Ia?BsX5zvk1gx(o3kQ38^PMqom`;&`#%q^N+yHzwwaFDzU> zDV$PekChyC=jQN-dD`hSydN4tGR1-%=<^rs9oUg2XJJQ<0s#w-P(6t+f#b$?h0j$r zwMDJ&6p_VUXj+q8{4FKepd7(^Mw%9EnhBA1h-MbY6uw7K_ zx;A)j#-6cwn!3V~W5Q;Sx=^1ULr@IQ8~G;->b{-95ThN`UfZyhN`pvS4|)cfbhwK0#4fLOE~@P+I>clne(YsXH7Z&MDautf-?k6TNw z6OlKYD?Wrp%ny*Cw%~<)kis7sLvm=$j`iGYBZc?oexxjDP*Y&X(=;IY{LQoG1?crQ z(v6sCPeS^?G0qGg2heUGwm@9O2M7nmWtf%m!fAmt<~A+i7X}G=FD6n_LvEq)?2Q?h z@T+MzuIN)Rw)Xt2QPBqcJSKGG;X41S0Cx&XF6gQTpWLBGX64jA%^m{(>S_EnK(D2B zu)S`&+-?hXMS{;4pkWtAmA%(GZ<*5_w0_IIRffD(lw@bA=T8OS>HoJoi5?MNL~L{x zzv4LAriWoFub>HIn8N~p@)0wD^vQa;bpn1nac43W%w~$)#lgvc%7~GxS50=B+eHBp zZHq*<9lMAfO?Er{kVKZw+3o`p`lv6GR^ZSv5_g(@64U5e>fGB;X9rrrKC*N0x9tAT z90Gpn^FXU;56weNdS3J_A>y4?gwMx-`oOd;L|;w+q+aR38U{dFd87H>m27DThZ_BQ zVd?_#=jEj+65sY-3Jd2|;+->O*)$$Z-0?sewpj_h@__ev)Hze7Y&qOAG|qC=CrN7A z+yFEbP9-6seSGZEO()~gt5v%iL_@a9rcztiDL0H;Lno^9OJzxj|#q2pYr zr&eqdwWMY2uU(~td6OF_C>$}?pp1C#^m%pCufcKi+LEC9)Ja)ut!vn#pE<)IFI<7R zR2DKQQBJ0uJ%y_@;FbeTai|aTtiO2{PLg65JBNOg30T)(>hAS@(u{5dDBJJ&|!9OXrruW~z`LJDnI? zZvv~5@My}ABS2;L1v<`TZa@vNRQGylSI}=SSS>8R>D9RhAh7j=UJ)zoQd52X`MVWe z+wQiZV#+k#rLZq1>5YbzDRip*&gvB`FTto0sVl^|_!8%oqI#7S6s7(ZL$P^Ydo{=V zriD4Tc-eyHZbgl!!7E!Po!n9xlPcCWO3=G0fp=Hvjpz}b|3i0hKtOw~{O-mun<16d+IT^mXx~N+zBe6lTcm zb0?KFUO3PWGI^Cto^@qxUX*DXI@RN2FN|CaxjRlbBq>jxvHvx+xiciwy!J(gzbQa} z^z3>!>l0>gmQ@aGY>Z!yN_4}_9=3>QU8=9J$k)6ys}oett5f`swe9K2TP1JQVlGtkry=}QJHO4wyBf8t$&qwGL+SPrDD%c@?|kqJ z%Y)~JY2QKvLPz~z?fDh<_7U;+k;m=rO=ub}q&hjI8V^B-?#p|J%5VGW3(FwBiDtbj zI@iS1^?W}zzU4h%m4dURPM`S8`3`K20Pp=@*dTndD%JGglRJFBHM@-eLs0q;K8V0K zqv)S>aHW4U-}ofONFk2Uln<0IjjR-)9SI3h&P{-qjs3y;b8Sw-jgf;2J9DCd38{=P z&pWr;(^>`PLQqF@ylN3|anX~MK@(ByP;biU_`3(X^!AnQh( zdpv>{^_>>UU#n`$9T06>h$$h1+S|!z#I^Iao3my!3xlYLqoe4Ff#m92s9duZ#d=%w zrYFeGE4K2uTc$pEitj>ND~3F2@9k@6YCPrk%l~%W{K_0#YuabhVQ+eGM2TyR92!%w zZ%8FcB#$SAj9{W5aJ3*&cEFS$c~%&cS~%ik;gau_tYZQjrsfEj z>n)UiYVq=rIn+Kxc6xUynY=Twemz*#%cHb=iH0HA4&FVmenMp5uGB1{cUFN+7xEcd zP91N?mVc)yOw6kbN37B;4-JYdjbep#M|=`O+t5mZFUyj@4^Gov*BGpp||u-`x1_$H(bJBQUfW`tFY*5>sYOp(9Sl zmf!o(M|M!-56%zp&OoMY>C4SIql+k-FgsOx8Opi3EWX5p9nypaF{C3Hbs{;iG~YdV zbJ{h82rA~tdA8r%EU#`96N){{_{*f**`pki_ZJA;%Qh`APP<$}P0R>M?|Y&Xd&r<8 z2=zvN_Svf3;48#wz3Z07--`jK=2Qq524v)W7RH~ z9BTsP*mPZrR@uC~JYr;1iNZK}{6_E+cB!b*8N(uJX`siu3%r|Nyj|cb68x5=aWcGj zDca=i)KpS4+LXb)45s6Y56^90_w3F0kLz*19~r|>3>U-lzwm}%T#5V=(Scepgt43T zTO#w+E6X}%7HW!uxR9Qaoej8KiY2egr>7TskIkP6{lE}BN(mYWnlLe?(Zrp2ERrnC zjn~sxMMj;3nkXjK|CTLQKn<%_hvvm_z|7{U)k3cV0)iy+T@Rt)B9me(vFg$?nW!X^ zkWqFIj6+eaF&c|K8?4+rrT)C2NJ(m$t*C}FQ3_rBmYk5}HyN`Rz5ZnrtTUH4a0{?4wOm~( zDDqKLHubb;9@t3HqQU(8I66lEw_ZnA|J{)ee>fjEu@LdWgEYsZ1N#PdT8YiW-(AS-wAF zNV1$7*J4Hts{j~@DWX>5bL>@6P9DU=C51uIz#hD1uRkE)hdPaN3b@nAUD@@79a^xzG}aA@%5|#ANRV@=NM$aPN3S9} zzaSslo*1-L8CeuSY>V$#4N#O_yv2k)9odP9!bsu7)hF^xi+Yk(>3`#-Ug4xQP#9ju z?*qaX;XU&&nA%#m&4zV%1l9~{1k)ztRb^ux=&(wJb{$Sos=}PBF*LAskbp6#Z|BAV zBo@Fc28uvh!raOlS` zAAS_{3ga@59TJ=^6PlJG?v7`iWuz&OZ^84XCI<@V6I+>3`PooZ>aJr+kt*oaQSY`i z7k;{ZEKKegxGcI%){L>trrcqJb?oRxm0iNocYmEpJP;g3s#ltd$A<54brr-mn6dvg z=gQcL4*huliMTUS49sf(bdKNs;$OMEf>l06 zd4Cdie8VL99y$|`TLwT&+$x&0gT21WnRAxUbSPc<^%1ajS4t|zlI8l7$49%UUP}_m z>RYmqL;C7}H)o$UjJG40eJgrZ5*AYI>fdfX@g7*4N>-7!nMMfPIuK9Ibi>)VfMvkX z`FKS#WyfZ_+)hJ$1tnJwRgv?f6L1hirc>;<*TsH)K{#!^No?`OAALjd{8%8QV+z$R zv@+hZ2W4ZYOp&!{N)Z=9ui3r*(FA zpH_IP7K~qXtp``_ffoE(oBWis*0-eV~*2I>YtB=iP;L~oiT@(4)`{iHyo=~}<$bH|Z^Q~_hAl3gU`zjdyQ|6wiETOQjjLx%+ zh`Qo;BSt|S5GUU=L|hceOaTw%8xzBi8;F_48(4{sK*Urh8BhC))OJ#rPFsKKH^EE+ zm_4No|16R&Iu@_1spS$x+ZcZ0K7QlXx_?^d`}}2#GKkJ;#}&k-YW*AR%Djb)j_R%s zbJ&wRX1t#rcXu9Lv0~JSN958(J~lQC#&s=W{1_A0;#q*7$!fWFBCaPjQNHOU<WW%W)aS~yqaYfC8sDx?}V02vWi3%xF%A7d?UII0kL4lyr(L4ebQd@Dbp7R(}#_C*lo z;K<>pzi1H<~v%|4piYv25?Ylh?NutcN-gZ zp0Zf$U(5-)l1QeZd!l$h`jdOKFP(U)WbsLD2aqyN9=Uqt+-pHV?^-6){t2QF{q+H# z^2|rjr&7{LN{r_p_sAnrc|h{5p?V&8o7dgxt76e`D!ffwcHyYnY{ZjWj7T)B5}Ds{ zIZNo=!^PVW>R*_c8-YT5nQ^`gChSX80D^6FK0nHIK-hB6z4d@S&drIA!)u}1a2N3o zMwg1jA-sbeGc8l#5t^qG(vdIT0a}*+%<}P~w5fE7mIIrS8TGlA8U3-7NxSEH6jS`$ zqbEa<+u7l%G6=Z*cZ6)xPAiE3nyk+c!?>$_F}p3$Fr;zD6>Re>=^*rYbx<^}BtYtIBagR(%;}Ux3#|{{IzlzR}OyK-e7Ofi9 zzKxf60Vms(i=&WIb?W6E(%cPc!!*EmGLPO3dj~D`tPB$4eL&k!EUHkQ`xWtfl}o@T zvWEyE3M>~dSE_d$>7<%r8F_ks0?=7DGz#xoSM_~&sDrEriY*Ct_g`y;ztXsp+F(1U z^dJ-BJkOp2mn_Xnz46hBq519t$)7vttMCZ4@7-P~4NKQxi9juLEO}&Ipr&}n&bx2J`j)K_{~uD}_wn;Ta$uyQn!>y+@~8C^3AOU7 z&`;qUvp{f4r7%mB2KAX**f9gs>ju5GfjdP56PovDgI4_E4 z4xMyD)9T)p)lz{@Vma3LEHl@pmdw8-kjKr0D?x0w^wK+3q6yVE86fdnAnLbZ3{XK- z&koZ+c%S->h`abV=QYUm{n|q`JRp|T*XmnZAjbnawNoQL-7*$+QpIjn$ zvU?%U_~=mgo0{7Y-Q}OFuxs7qYb>tqFWQ=;@y1!Evf0D+gl{`R+9U83GjAIVkjM8} zU-!q~`~%YV6o1V04gh{d8rBUxAm9#FaA}TX*k*VS2KQ(#2erh;%XB{J2&WGM*F$d} zoj+eNh|#aH@k^FN-67K&4SCQ@rWaI37D5^Yc9DjE*vTN$4;C5aHSLSi4>pgB}jKU?b> zzg0Xz?qM<%RwuXf=|RZb#*F#7&bRmr#ePv&D9)7m2%0wZwUF%t2WlmGst{sSN){`31XGO#qWbueu z$<%l7zt1$UQ2(#~?7u$f-@?SdV~K@~jP)EX0b+XAhL-;e?-wRoDPSpmoBguMq*G(9 z>HnnSodL2EtC^LzVhNFlyn~mQz(-MUOg0SlHR`uy%`Bw@4B70G-BdDS8ec^0Tks{g zU0qFL#$S>$b?t17Z{B}pI!yCC9Zh$8z2WrWV3(l}2l+{%5HK7m3Dv~*a5f>L3;v$K z1;0=A3#L@Gq#`eysiFDB)#t84G8{)A9q^)=!lU;$(6wSG)Q=85Z@Oi60i)`0{4u^l zo7KD+rc=&F-H6A1p(K43hLL19-XMf#VIr+_1YUYF37v5K5%Le+fklzFX%_a$5-cCR zsS&XbokRXWW!ke2t;j{S1x(QH+be+$=3h)Usvv6y)AOQIjd4&LS>2%49HF8ws-lF2 z?^&$wqjk>?L8l9rF>AMklQH?OwzdVyRza!XvjI&YS?5SZHkgGij#)!a3sxNL7ge~yI1(W zA5<6&FAxZON}Vw0^XQkKU9+ytz62tk+=H)1kPG*|l!;POzr+({f6B+&?;{ti#NzB%pH`_Xh%O( z{2Z;-gke{8MVr4^666p>mTP>XncZlw%~N_EVK_FH=;KJNASZ_%uS(bm=?4|+d<;U%59ME(P>fkpx zN8QM1y$0jFwiFk~UoVP^;ax5zdpxpr9BkX1&zppNKpt+t4^~sI7?59t(h&u!jh4ij zh$WEl+yWz-gnWgpU?9e!Ughu%k__RjrIg1oGe{5#c5tLc6E&3TUfB2+#&Rh4u0OmK zDOe!@0;L7<<4)0JpBRtP??$zQhhVw(NIG5qboe`G`nMm3FZ^OW_2(u$u)`zP5)IW% zC=4xR;;rD!yJ+x7xmRWA5EUg-1{w_7xv(2;rzI^efbv~4iu0pgKSAtG#Upu}&V0I-x^dznv~ z2*C06J$DTIF&@uCACcx1Z76R(y!)IV3{#R*n`o{-y;?X5{83S@f0x!+B?)k=K{3^_dtg`%ZqnnB?2o z#y(>&dD{M#143pLyypFw$3H zmy`%o*VG_e%V9dMN4QScWp6!Wm;bf>Ee~y0JpEzslaY|!nEx>kJJl`-1Rwm3b4k9q zGTReXX+aexP?suYA*Q<{NxU2rP*qm{ZA;IZ3n34J5>gxMpUKmTSlRqx##6cYXa5TZ0- z#{`s|05Mr=uwzS9oFHOi5T}6PY6snWNO@~r3bRNQV&Vt|^?9P!HPtaq16dPu2Mi*TEF7foesR9iX`?2PmIzgFYs#$L?=_g z6u0~sc`y2SfSNfU2%6RYJjcQv+xgcv0_?@k$yD1*=WWOwa-i0<>@x9-IuQ zxpIpp1i(P7!wW@HWntvh1$o3}$eTF@N*gfJ6eA%fnHLSkBm&#s+}+tHBzRLs#9Ibx zkJy*6*}5~4Gm6b{&c^jxR{oD>L}nZcnv+p-o>AG^$)&8<2`9P>8HD;f=o$|9ppW6 zNnE--qCxb!?6t=P+hP*m3f7`}y9-U6g^+v@~8 zYbzyWs1{(<#t+Ci4+Em)cy$_}C!M2~mE;PEv2ac;uW4JNaM#U5Vgu!?K8m9E9kB$Tj8p#fg}#9ykh># zvdGgU=b?zRA`dyssEM*f*YUP9bDq(a>t-^*UuE+Z>+FGT;Vq?_ccpdjPl;k%$?+G% z1R9KnMxZwn1oZ6w_~D_5wM;H?6>#fI$Ke`*! zsdm&qsQuD`swUSrD}O#QE91CskQ8mbxLd?J!rcCtmit>2a_9QX4i%w;Ut*v7gMi26 zkwB;kp>99**@DCfKlUty+y#QYQ+~|ZnGHd$t^^4XnV}b{7_*XuN51oK}R=v;k znQhXCucX}X-w`i;QWjX1lo!2)|9a`%uAzeXN&}Sxg{IjD(;Wkkj4Kp?rct^@kd%=7 zw02^E?kuoO4WNm>D*SlweR-1$(Y2vjj~4Q&ch2u+!Bto## z^23)3)r5mz5%}>4+0r32=m^q>!YPu{R~U%m3#$BhZ8tQ@pXNPCCxk(^m^WJxHK(|- zx;kKH&5lmUw8%r!o(=R_(XrQNPQ?D*m|+DMg=S5Vxnu{a9Gi0~SS8h-*h1cVvA z03~;h)Pq%9W)JK7rZFGpy9}=>A*;UMkm$EueyR=#RbU=)HSrBbI-e#sx4omHepc+L z!BURdmzJRW@&1CTw@+2LQSI%31Zfjr4)Oy535QHVZ=h|KP{!xRZNU|+UE0&K4)8U? zO0Rta5hPt{exC#CSDXZ_2hm%V??Y|F@F<|uY&%BKs4wwEd&it8jo13I1RWpt-i#wE zpFx+Fts_Gdv5X_E>$MYfuyyFgn^YX7ZB#i-#~rVv#(~JQrAK|6h)sHm56fbvbTx=Q zQoe0$qk{butkZOrF_Z?7CsL^lF1O-9u2zz*S*r;3DmusJRXUUohVBp#!~KPiE=P92{K{FdSW3*Y>|~kG|CUi4T?q>ivas@r{0r#F0M86`t~i zF|>7xv{NFA#o^4F!1X?~3KBoy#$}Ht^2aVg|Lk>Zk$$tgLrD047<;E6(V{3xv~1h9 zZQHhO+qUgnwr!iYY}|{D| ze*-H01rM;5VDSI7#}Uz8gP=MyQkqWJBQYPzV=Tb%C%!LhUO%dTZAK5eUL z_+}Mtq^#DxCL!PI66xg1RJOeHBL#cj{z;Q6#|%*3;mPBcPhd8^(<3RY{>iB^7GAs&=3kL} zklw-1cv>Mid8bDdSYL!j9lP8^^mEbk=&57C589=(Ei`oB@Up&e(Wi*jPjOERe%uY2{PWq4D5Sg9(Ig$z!!~D1{i^F1KMsBSb zlDN$h&8Sa`E+$N3l0{s6eGDmA@(1^7`!4_7Sbc^A5a?Cc;)SF93g#$_a8b|5G?;q>O`=OkoXxW`X6**5MeNpKW6!Xzm$r>2 z1!}e zO5$?95?y{x9ZbEzkmos9>Iw_-t~M$>3bg82%oSr9fLhiVc`VBD>BtUC_v?5@=CrG` zh{{Hzevauf&-LP8T;rN>bhc>o4i>U^@_fdkV5iDeqxjLS*scBmplGmZ8@u=kQl6^c z%1wMJgi3$PNjYX%nh$iPX;3uK6wC~qP_fFhEs-Q|YgIH&UGA8fY%Q_ORp%|*-{k5I zHh(|n#I+v)#U*!Oe=P;wKx^y@!^HJwsN64%+vXUdpLJ%Qnt|Tx9)~qt9uHC^=)0fe0Nk1V^eOY7->!JXpFW#!e_Eb-2^-&*t6`5&Fs6YYzs8pu_sMy$ZgRRU5+k1m8<7fED!-R4^vO(|TK0ZX}VoxzXqkjtJ z^qAh!y_HqSls-%7XKBocj*)jC3rJ_-hZ?Zm<}=VONtUXqc5wBFVPX`^bP&)vDh69} zO5Au$y}=p^8hi#)c*NG$(8YT4uhQCTYHf*$G^wiJ5rPzAJI>Xp(}#mqpg_d?P)W+w$97EU9mAa8bM`8f(wWl*;;iOlZk zRBL}s)~0fvrF_|<3#BQ`CGw3tQ4_G`;u}pCiDOR_EX9_=Zw9;iAw9u4p!&mn zS4u0_N!>@8n!|9U<2I-z8S!2WMGHh%SKDXm5ZsbnB*Ed+J3PS~(dE$l2898K9$zq^ z^T>F0s~v8&MF%Vd?ycC~x=Zy>VIsDF1bs1=${?S8G?#p#o^Aa)YjXsJF_+LGo<|zX z|Dj&w=ha%9ImluzQHOZ7&|Cn9dTC>Jv84%qp%(ONp|xliynGb2&KfvkF6|;++)ftW zsFVvsxr*SvnZ5e3-M^>c-~pXduqliK`scsIi#(9ijO6i(%+M(^BjS<-%{Y}rD89OJ zwZI+bH+uFo%SFR!Itd&9B+-(m~VaD`=SVs`x1sL=ZwJ*AZJ7T8yf?!7)C<6omN9{Rq;{E}~NGq`wk@_SJ%M1!Tn{y3|VG2u-k z$2N|f+9nX;-Gnynkd;2L**Tx%AsE_pjpZc65Wpy%6Gz7kXqlwj)ceS;FlxX-Sntc&}HKCpW)O1@M?f zZTkslXfMjSj^d1SLXLHusPR*3p#xmHC@>T?8sL2CEP!y~hEgnn@|2k7mhp9{zt zytSU*34&=VHKj~{Hz7JU9mE!>RH_g^(6v~Pw0PK&1=-VmQd}tVLWoM{?<>c!3E8>M ztXo}73zy>iUUWHC=~`E(W2blD#K?T5s6xV1*;hz6@`OZ>a8RqF?l_&Kb7XM*lk_*} ziCe=Vxkx595=b0{j6p-uhxHW*zoBG5W8qGA6^XwCtw;FJa}oxI`*_v#Pqln;cS7Bh zp=wZeZVMR4Mp0dYtLG+K<+i%fZ4*QOwf`@)LrseI|7h*UW}oCJ6{rbzIw-Y8qSRB;tO7lxe;v(b?kp*?8%@?pyR?yV zzrg$e_ygp#FeH8M*559=@cZfavhS~^Z75x)Xe9BuyianN`+odOoBloSw%r0SKub$T z4Emspy3I8IpF%5j0xZRe*dXIX<$I{}J zXt)iqxTX?OMTU-&6xy_dBW;&?;qoTIqL^J*#g$;PiWs$_!&4mNcFH?*v08EFPIpxq zw_1!hukhmWoBe$}AgM~BiN-@X8^gt`skON&R~_44s8nMvS8kirRhc+=N01;8uI4h6 zq%p!S?9RP64#OlZ-5a{T=5B2G8(%PnjNsf0+MByse)O)^tuu`xn30;GYiaaYYuZV@ zHuDIXhx>-_JZu0Rrqk*#-YF@oacessDN>-2WvyEMb`<4jo~~o6ew%rsckZ&d{KqX@ zIU%4HWtadjd;}#Y7$#8hy+wRMk`jn`0iByEXg8F?j~wD#0eQ?XW*#U`GAH%!e5Eis zT!7CQAl727)N? z5jOa7&?mYhU6x`YhzM4t52pnQft5hK2QmUH1RCfW$DfcN#k5>d4~2pqD=3=dLy&&r z%NG2}9kX`)Q`7cSH`My~mHv+#;>=#-=5{;tE4H7)t!u8ZeT>lQ0j$rS3B!sJ1F4!3 zE#CMBYzt+2^*YAS!q^1}#qg;-&2FiY!zoiT#%{ut&rQHgiq3frFmn^|I|ASQjkuIC zJz4u_dGuqNa>aa4Zs&D!IHIq=eb!syK=cY5v}iL_|Gq=_xoS zZbrpPw@=5{IrOXI7PXh|bp|nly{8_s>xB8ZPIw-#^(yPvn;*AAG+|AV*mr0_>#pC{-4=@7@n0DKho$%y-0w``v(gTcUXO#ly+4>+qKkm&W;+-Dk0ih`ouau3Z7iz7%7 zm@JMegM}e<6Xr`hKKeIrTF`j{l}5CMz(w7LzMi}+`v4l%(yQk>h#6cJ~ z$8F!j3fhk6gc}i3e~m@GK~oUlSBUqi$5fIaDYly@U24t9N_z0(>8f9j;flx}6N$-W z>O`Gk@gpcEGrii?q)&kDv13?yx;x8bgFI@+fW7CHK>QYP(gOnvQm>!j<&ffQ(q+^c zLhovXPr##_PHe{yC!aa@3riEPMDxVlWTn7)SkUt>hCH93Zk#*(@`1m^OCAo>^ zjE*?^_EPPukKvcVD=y!VA>-JUSgT(aHiLBcYyKWz>po!TT|xx@Z$QGi6)$4y6Deg@ z`rpDSj~plt3D%9~bjhk@luUGAAqu~T|D#0tAj~3Ke@k@XmlY%bzas{6uC_-1NxO%t z*t#Q&V)P`NG)=fHrl2A05}?#bqIE)1SOA8m88F%grl3T5{bjkaY@_Qkbuapa`3do> zq|XTsEjlgVy<#<+m}XSqCmYD%K`R5gfk5aHQUNgDp2u*#$(?-Ym+m1codz`+gj=<=$pMLUo`_nK zwowfi)153OKU@*nbo7TeVTGa{25u`?6bu4^w28K&w6ogqT|=?qTKr6nH*Z9onUr_b z9|y9fUnIlvZ6#H^OQbA0m?S$^_cS9J86wGs?(zIOE<4+N#)_;Kr7%a0lT~u+59R?O zvzZtIg}KsTXpE)Cq5`$sYYyWA(bQbGSm#Ew;=I9bjJNwSr_VeL_LO}_9Ueko?G4b- zgpUJ)ZTH+Ti7S(=rTYI*fkI;GdP|wl}hw)YcFM zEvl;cxDGZoQrh@;pvUMas1$hcV~LVey!VG`bOw?}#_1av=fZvEV=1@3twjfVwKGp8{Wd|%J z7xL67N8Odv<&a4ovOk@`xzv7#{wL6C#UyW&Uf0eSa4KI?xkRkN;Z2WlkQ@R-bILTu zo#ljO){3W`%Kgv(11wCh(#N~{g|+`j+&1O^z4YactW1qv{u9@ZRk4--71H_Hy)M+G zFpi3huG(%Fi?Df;z`kXRM^y})O@34ZO}GURTi zq8mDHE_i#%<^9V!&2iqW^XKycVhApwFv>ugvTcx|JR5WYKWHaT!^Ctq-AZ=U7er}d zIze$U&>}nn#(ZSLoBTE0?y170RIYL|A31J4(P9&BRG4>b@!4LE{Zw>GBP7gsS(Y~* zx{13f9>olUGOfxwH5IPo+-kUR%RHryGd;YRvvz94JUx5x$)MFOp=#w49t3B3gm7W#F$Gs@c1V_^wrVSs5{Ny*Bm zI>McyeBezdO!(VP#J1=>Sfz7hI$pwT%fLF z!8jn3NZMqh0k_;Xxs7WrJsK1>reP9+(s4+q9alvZ2~E|Rs4!2QrdO=0GX{(LHO??R z>lRher|OTfaIHr8z-!p$Vzkn@> z_4yvh4AX2<J#1c{PzkWE5==OK2kI1<6L2e{#!uAAn8Y2@ z=s%5%>|Kn1mf}|^|8abLW`Fm_$yM<{_<+Hy%n*~^oGb^s;I|_=3r>VT-{1)G{D`^T zCx0Ht!f^4OJO^2~1fKc?*%@8f zD7{nzpveCzi`yn>tYiMYEmwYbpxFL@m5hX;vxTIciK&Om|ME;vRo;|FQN;N9!+Chq zdE+Hp<;uL>ywakxI1Ro?7uIR`Qhy>X7}pgXcl~#KngY_$g)kDLF^Iqm0n#gy;7lx} z=aoFvWS5is+6r=h=x@&BpT{q|$LrTTeKvrn0(uDkjj4TMq6jz~*oBLXa@UWWvyy>zm2 z7n$uYnJ1d9u}@_DrMy^Mx?NsY z8HFn6Bga*pTJErHuB0)od?E=OrE4g4rI=&^B1#)# zSTZSFlq$X~CMZV@Qq=f75$~!%&R?*gXaVjIlh=#5KCbqIQ{0y46UfX;IRwxPAG0GK zv{}GgCBv2zNl4Ul!Czrbmcw(j<5nN?qU64Pt-ZnM1=WR0-L>()aa$a?lZpxhmP$Ax zcw3NKT%K18v z61kaPO23ADffIU)fpk$hD@vwiMJq<2r}=BK3Sq<_%J_q76^S8X7*i&E)-D~O*U0ww zjaEboSxt-@q>Lij9sU^N2VC*k6jF-Aa1 zT2fQ1eo#4hNQzCX!ZLa2PfdgJXRgR+=;uH@rJ_604Sn zBw%lIyd0UIeDeKJRyk)6hSu`4r#179q?KZ&=TU_4iG7JM5xAvReXzqQybx|1tck;z z05c4*W%F6Pbv}B!OAJPP_&=EUrk7a(elQHJ_)8NE4%Sc`xnl^93r^u5OWC+mBJjU+ zekOJcoKb)uAWBcV6c)&#Ny}tbCAvlA!DBWn^!!1#~~0cfJ-=#=Ko)7c~O=vx)okb5rRg zL+=#Q)AD>!x`7#&zFX6jO>byfo!XypvA0?OET|S9#c-l_^Jk$ENhwJhg5?Sd zNm5DN^Q&&lmxbWcoxl9_P*I+=1dPZ?C^UW zX0Kdt|27G7^M~)Th_I7%wClKuR4CmQf-NpN~@Fxeh@H+!tSUZQe|F(SkL-3t$iS53JmVTc1jC}@s zifC5L@M!uK@%&2nGX!p^{B5j#+j;9BVf?Kr2=Z6MhXT(Y68O=ehe4QDK)AGk6#?DX zb_bA)uv_2V->kb11{7?C8PN185|(kckY2{R3Y&ecCLf55aUR0kme|IM2JX^Ar7fgK z;rz>^_vLUzcG1quVVgsP{tWXkpxQz&*+q*Ewp3ME?#nv$aob67dviRLuGj{)zAXh} zF+GY7I56~z2-H+tAv(~;HzO~VhZ%6pt&MDCm5y6SG`|beep@7rofK2|vPw9~V`efs zR+h^I$C!>sjQ93GxwzTv(R!)36EEOx;jkPbVS_kj9e%euue@=~YBCoA`g`lLED$oZ zH4?6%MS{7lfDyNpExHhN)>F~qG8HCe%`id;_BT11Yv(iL#e^7RK?2T337E6Yoy3E0 zfJVvPLX8FE2BsO%NC447hZ8&Y6{Au#bBa053Q?XDq)RFWI)k!%2gF3y&Uf9&T zt$+S`j(V2UAO_2Ps-F@EBN~eU9beoMgcE$=auspAJGO}qIs7Kr4Q-I4lYd>`MvSl{ zT!?{VhVWj5a2M;>D~A-UZezIQ9P=(hN;02&`CuSK;qqeTEZ@OfySjxM(T2%ewh$H$ zsmouCTUI?v&JQUeCB^)y(|w+Gk-#;kJ7^AXCRW_b35 zWyZ8}#&7gcGIEtmYp75)u^>amnW|ZHGYl713kKCJG9b;e6j=(c`$%?pCTAWHGhA$t zvSZur;a=@B`8Fa2EQu9G$|mP${hnKo4#_jIe`VoVV~QVP*DOfyaC{qBm z2<;stuny7`88FS=w~iAPB9<7S*5+Tll6o>H11Fbw_7X6nu0$k7CT#!StDQ&6@H%2( z!I=%E=R>AgrVgQ}OLp#8jgxHO9UCRty>&7OrgP6_2rrY;e#TU~L-fc2uBuY9$Cx5> z(paPHVgqv@>f}zz3ziW7*~CvyRSM%bLlIEHQfMi9H#Tb!KIFP zZ-E~$0I0RamIXHZzL6Z|Qe7dZl=f1tU{RB0S-yQ}8~mU*!sG{EIs8!SRcA%EpzgJy z2_HcNpS&&M)>1AQx?wC)Gh_%`teTdE8aqM*oPIvNv$nmHw$v8Nhm~I5MtC(zj<{T2 zD2$XWEs|bRCc@UH0Iy(E3X*I+dPIlRZY)jbt>h6-h`Fzx8~)Q+w0qIo$ zMW^ZNb}&-~7X1q$djTc#c!93AJ-t{%L?wzNSYyRA@}inaVeAz)0pmMNYd)GF%>Y}Y zSH$pDe3rZ=@@TGXG@0N-tZD}r+f@nL5P z=R*y-6rXbmcq0Fv^q8E~sCDC^CyD6#beDt~m=Lj~*y~bn-;pnhvynB|9g?tps`!Oh z#_U+vsnJHLgtcGCW^$|1IIT6h4}GKbm!dhuf0`e7a=_eXMq}Vpye;^LI1Tz`w}~wE zT{2g=!N;{%V;?9w|*uc<&L=hB!PM|C%v}-QYh6$wOt!mH%)Y2oSa<4 zln#-qRN-fM_5bUTXYm1oGhEX&EDy7Y?1*o zjhwcxH+UO8xb?H-S2xYuUEUV2ZvDMc^>uQaJze2$_TX1|gT37Ud5AJ6!ewwm4B1=a z_mp2)eV**^DcV=R#PW5r>@Zh*efr5X86`V0Jnu&mr&A}?ORqg%zp->oxo)YrA1u!A z%cD2(@%vqo4iD(Xkg_Q3|FE^K7y| zrE}S~0&&VwHl{MIBgC6Wgbs0?q?o%uJPsQ%;7#4d#E2Z z3#sf_|ALXexdVNPPtF@F6%}TG^(245$J2$2%eT?`$yuTkf} zantf7C(HkoGHyvvUP}giHVIBTM|6gO3cJ8owOCsfTfD2^aTIVaO2=Ab_r5h~JGGLEsbXyg!76%QosOM1uQ zmd+~qIdvA7qEJfK6QeNi=4ZTHz zDe#TD9V2HCiPDBgAN(c+XPquI-H}xuR;#=;+*Nv2>aos2vucwdVf8 z=$zRfE|y_Juh3K>^bWPOa8jVr=Gx&yuRGh!c(D zf;(Kk&&Zb(h~#pN5Fhhx&l908nC^`~iE+sUZaZ1|jrmFNN7B9lOxjHNF=CEXpZcgr zpE5n6d&+c0ExFOFUX!)-iPzk!W{JYqMpKtgC`n6_Fr`o~TN|!y9j;^()l5ZN~2#mY>Hx{XQoL#AICk!xH>;-8w>CtT5TSI&G+ zVO|i_yL(n&AJ2alq?X^s;!dqWA7Zg!{ ziqVZI1IT=k5dluG8P6_gg&g zpor3YQN4@e)vc$_@SQs)u%1j|JTL0-+Ojs@Cw{w+*mSiyZauH`9pndX_OHLvU_Iv} z%|EV-|Li{crTIR3!oT-Q;d!6L>7Uy&d`OOr3H^~C{Dr=0j_8H>5FgYD{gKu3px$N1 zf1uyH!uir)pb38v9!e7GLVReCunBjeIIjwBi+K-9E;IWR)`u`XhUh$#DM_RyTEn*& zynb!X?kB7L7MOW*sBLo-eBl4_xRm+OBsdm4eMs8}Bm@dYK}C9$KShP6jHeh1Nrl3^ zI%GDJM{*H&FHIAha!d{tZS#OdICZ2`dsK&iHFhfT#Xa76SjwX*k=Bt**cT>94jMJ4 zm)%j?9$1loJ7*27}Wq`ww5-IidQqliLX8`30} zwvcyruHjK=2D5){*Slbv(TS0{hSqcm=HatrtWgOdF z#EZ-@dbZL8(#!evnQ;yj$_Vjb!!}Rd!G+UQglBCdzza33LS{5@kT0fZ$c{{Ap~8ai zIc1Jf$%D4nmKAEa7NC|NF7vf~-A}=oJDKVUO`_%#(*!JB39wQc{4z0bAx1OAzNv4f zfafz7S}0P7R%$`gkrnOIcImwnpoO*BXklF{O6v1WfHz|v#}*8!D9@%HFfJp?4VQ4ptyT9#G{sX!2Uv(WUFPGXjPep zNknj!`Qf8Vg^kH<&v^?2Y8q$_+x>V5-s5rtz$K z+TN;8>Y{B(UoS^cBV8y1EPGW$*nd)*hTxKn<1cb^KI9SNNq~HyQt(Y)i zLf#@WuskqvI3bPj4$+K}t!7#O)*PhZRs$9^eFPi$s9kE=!ay|ZLx8_nUyWwc>Lk^J zQk1z%HnA)E&g0RxP;RVlActnc>iMEN+I&HhGDKAyQA{vhK--Lqc%9P>Cmw>=>Ug+` z9(kxug^l`MnCQE0DcFz^@rU)1k_U!}f6yDXi3)Dysvk47JL`1^JI4TeXJCi(7;H89+Lz8 z8ZFG`P@9u0SSm_5W*;OJT06-w4d1ys(m{<)4W|=a`57&k|5)Dvb!xSWYNo&aby;{d z!wRejGQRAlO;X|Kj$J`?MNCCp-*&I}`4)}P0X1Lsa=5K`0wdah1N zP_Y+rlC-5TX$2R0EWF0FddRpgd5gNXdI4^ez6GRP<20~Ev2RZ7!kwhI{GO{(0!`fJ7kO6 zBtBs?^a^c({9js&W>SpctTEr}y;3k;8H7>yP9>e`y+m>KGD{Z>mjF0y?WrjkJ-QPZ zeXw~-JTfphDW$*|liN%`c-G9Se^nB;~A!xnund-0Ewc$ zn2$fNn4WT|1{Wdo7T&FbCU!wq`cWH8zMeZ6ps1RtZH#Ixf|k=&F&{WREyt``ss2$pr<$kRVbO9E6}k|q3D}@oVk3Aas`Y5?%R@)EC{W_mKGvT= zSu(k+yYx|mZemBbcu1jT%UO`LuShSt7xItwz*;(04Cw`0SvQnDdp=F`lm%VZSWu*(~f0)xW9Ml{)C(EPoB_on$i7h$nk4#1rV#2;4{?< z=1jcsJvJPsHGI?O^+u(PmQ~JJAZ4YQZ$09{4OQFSs)eZFg^Clu%UdVoWXjGBFOGzb z+9aLJGw1?~of0O>?&#fxY&dL1%LM{3pP6<}mHD0;lFLv_Yrj|%)-BJD5a(K1W-ps; z4(?PT7XlRP9tqRp3_20^p9DL~(-@b>Gm@=iZpX#xvI3M+2)k5W4AVJI3~}5;j8Vt2 z_H3wQnxK0$)}1Ku7R_hHT-9i(nhj_d?*hBu?7orC9+5T*=E@$KczShPOcNbJ{=qk? znAT)y-a^A~-{I6*r5nIW3o4iEqG{pp$(|I|^Ihrn9uoAUDuHk%wlkm@D}ys3ik=8C zMcULkqk1B$#*F!2l@rl&Q%onAFL2HCiPlrCGQmA!{kTK&nC$9dsOdl0Hy`3J5ET|5 zq(P>6xwaPPXg5B4K{C}B#lL9tbWtwg*YGXACwcb;ET3hrHisI zO$XXCZ2&7Urn3T0$G8RiM@nEd{Ud|2@0^oa+N?W|EIXXvQfKh0-l-FXsp`HFLTwqq zQ#jgYaZV7WKLnSjQ9dJYY|)HKfzs#g^I;VV22>rgVqe)%;8#U~R?^X*q~J|23j}@E z^ss15BI64FCwf$AdXWi+-!VNZ7q>T>{dQw7VY z{f|;M=c;!R_{12srBGL29#?N91T3)GJkXom@Lu%8VDx~EQvtTXb2cEk)`7=h0;nOX zo2gY)(KaA#Rv^W%%-F8%3bS8f7dZVUUF5HT3$u8WQZOSg*QFdh)ZdrEn%hxX3wIfa7^4Ph$9)lis!^mUK)OeA%z5=c; z@Unu;rQxGRl)tiV3o0*^4`c6oS>L1E0w9)D-k_g$KCIh*{{kj6a)m8WgqwhS_n>d` z@7>VD*KHU6zq>sgyL>|MdmL{BaSJ^hQ~Vb`AY$*H%RUz96c82tBX#J8F-Dcre44#oSRG^!;$S+;)kG5P)Hk9%{h8SsZU%B1K1Lv_Jf4GLI%CD)t}fVtM2`ey5bRb zs|KD4j_!aS)E%A^&$O{l%BOdflo{8pjNJ0!SAx(@732Zyt%n9|Gm+~RXY%@$VEtBM zEly%U)tOM$!!|M*rou4;Hsqu58bHg9oR*BaX~P^bDiTlJ?}oS-eef~-0Hgi@qxe9F z{6L5C0rzA5Z?pYx^!;zhTB81zd4Pv~MLa%nP_Lj4-{1*fNEL_F#bI@U zSL_bQLr)C8;NW~lz*Bd zQGrR--^8vEhU6DLX10y9v&c6`F;j-<9vst%?ZCJWMn$ir6P?|SPAhb$Fm10td0Os! zZ}_rqUqh2re5>WuB9xA}4se{B(mx#esSJX_9O+;Wd9X&_;dsTYd26;inVv?=kSF z6^2raLaX+4U}&WXL>tZ(qG-W{qnWZK$rnoD?a!I$V97cxu4b_mppIeg(W}Mfp3?il zoTn%~R<-OFO$-^A^Q&_R`3LA`gAugxmE*#3@A8Z8;cY%)*?Rd;JuQ|Xo?aA*N9$)V+wn-cu3Q%jb?e56n=QTIcj^qm8|Ot7SsDNyDK5qnU@9$T_R%9ot;1fM+ERPJ-C zOqFr=YZa!}4G=DH@j+^=r<_wx$=6WBuX8>i>`2D(RLe-I-Nj47iKv0z2lt@)#F8ibyZqJ@XrdHK^KhX}_sCeuYdhE5v|sC*%&2P|$@aWKaSD z(ZdRTK?MbpNUZG6ENkF&!LmCP?Qw-gj|-x#$M+)4?N22|`AHEcHTg*X*JJ{9sy``H z=dDSqWTVb&309&C|0AEas%zc>eqoYLa3#9HGPEUxehiPBWtI(Hlu2ThzFj3+{JNG- zRZB*ZQ`w|>FP1j0ehJ+P*4eH4tW=A-Kn?ypKra-f8#mO`tE+(f9;>0utx;+BYB7@<#P*N`L@Hi_{&iLEvMpKS{EP9@GR*tFFd zr(5ANiIdI{o_X=hW2kbv;EcouIUY3%H)rR$1h|@8@yO&b^MKZn2c|u54sfm0Ch4;S%rr%W0WWPe#{+o-rcls{ zuP^Krq=4XSbpWRPZA8hi-99Z4 z#kYOSyrWN3v%wSQkkwJ zB=43>euvGPuwSt8+x!MJWwI0M6KF}N>Q&iH2*vKFPlW}WQC=abeel7E2E8_SP;I(` zoWv`_wd}$MKt+(&V$L?l&u=BeL`lCYa+_c94Dmw8>J2a2b_VaKVUJ zpQXfQI=WTRx?1NFhfUPyCCPy1c7WeJtn-1vN_2^bx`f|j?-SSXKU-@ibSuOHT45(g zR>kA%vzW>%Gs-foOEvo4%jYeLj);(KuC?JuR}9_uuNYT4IXLc6>GMxBOi*Vfo+ z|A9NU|CJg1x|bsHmqMvpzfp6H^->dZC2eETUAf}|1j&BG&3f^KbeNte_l+Lsz?^f~ zo1&^dzn|&GR6E$JMld(-@`)kNmorf>aKR}9Kf_A)r zJJK_vu;~Z#zk+6e`sXWFe?>+izapdm1~gN4ak8{C{|{Y7sPcb^V{ck(wa)?Vl49|y>EF> zc}_V`IotUCeZQd$uwGGq6;;Ah20DU3>P_QDLVXL!ELE2UJDQs-pJk(A#`i9{ zmK>@>ZSR~+rGr_x3^6p>JFRw^aXrWyf$Fca(z{SR>i#l$8QkiSu#d-44aEISrI^L5 zy|_xb4TFxDE1n7TlhV)u{y?T61`2pLnJaP@-gX4WVT8uusS>#+1#dYpVm4>gC_iNy zrDh;4r4%5Vg-F%go%$nr0d&oQt_@_uXt4CWlnv$@k*Lwg^wZ+V|eLeOcgStF`Z8 z0G{u9n-~mgh~<9A!+p3)_|^hnFFYmDn4Fhx(L8*IQI^%C4ylY0g%wI#hk zE`UFfI!5(=C7fl8N0Ce$WIV(g0i;_V^CbfJoBNqa+|a zJvKX8s8RcdG{>`?N<;98azqWQTJ4XI;%MfKa2{~T|3j%kKkJDYD6ezW!kkUD8pd24 zWFl;=khM>V-A8g=5xGEAIza8Q2bOOMD8Z0%rvj1}+mmU+?fBzU3Yr&r?=nL4i5(@k zP?_57o}dK#{}A>~VVZ4AwpnT0wr$(Cv(mP0SK78KZQHhORNBs)=bY}o`|Q5m_y5+z z|1jTTMa&puMU0UimS~mu7&m+3Jr1|#YNY1&YA=w-yaxfJBsnvfOb>?fWPW+a91Mc^ z_Jg8PoQD_j{)JSeqEJ)`8wswoiz`3o*yw)|@m)|5k$(j_CzEK`hnlXD^z;N`x2^ zu_r+YIxQ)_9f3b4X`?h@i+s%8Gv}SRP%oPbH)_A8w(?C&fbC!ng4}@F*Luen&gVPr zbhh%fGW4XIc<&Q3H%`B*S57yc@tsf4K`5k8;a(cL%dP>B#Jl=nJvVR39%GCevbM@~ zM*tcyVZWG|2XK>d-IBEA^igC-0hem;)LGfL@k#M(SfoX3z!m}gpQXE|>_u&FLB09e zfKyDS*V0||eU8p~W*Rj|m~kiIB~w|8l161&Cb>dM#vu8W%L(YXwvirjQX+UBqtp=3 zc7E&eO9jn~I#MTp7L5J{Fi58THl7NE27W?AZ6ig8TU zFevhpG;=#eJyR)L6*Ff=LH_$XX|nK2WtXMr%-H)`L;Zs0G^b_{=lBUyh!85l zJL-*99JyI#{hJCshR+b=BbahII*Uy?4)K3;U_{6iPVZ*)$l&(1+k|T{}&~A-Ps?8OT9MXkI!L=#X_6*%j@4`%E51dRx$yRC^dy;@drwG9RTrdL^6)zvqp`cRrLtPW&u4;B?L)cJ!wfRetD8)z0Ox`XRcgf~o(KFCAbk-_ip zu@TK>7V|?<#Ls;}n-);`FuzgyndhYNhW#hf^h}%eT^Q(YHe}C(S`Zev zX0s)(B>bfXfK3gdwmRhk{>C0-OS`JX;3h#?DO}$Nf!^kW&h#=FH+B| z7KUn+ZaW~6iufmwvO@#psBefQZn@y?c3%9GGQmrZ{Aev(3bJ!v{BU`!6?9TZGvp{t zUi?-6oA)RzCDN9qCcjmMGpcQ?=)`@4r8+c#H64%zC7?F|UIp|5I%Faw$SZuq7{8^U zKWr#q6p?2qKT#e((o8j)I2=g&K=>aJ${;|Q-co2MA@UiZJbto>U?ji=WXOAQ@)>4_ zfkFN(-~pMMuEq;W#CkW&9S@`!0hAc2*azGKxW0OfRAAM%a`cs3|D3``@Tj-7p91}W zOVK1tllmV9Z*$9_pPD^GwN0cOe4#Qxl^32SweF}|W-W1*rAew*fs(4+5n*nyQBE(U z11cNjKlvlv5ZEF#HYkq@oh!4O@}1wj{(EA3ZbVmpW!W9)6X0A)KLAW0KDvJVTzX`MyqGsbSMOP><#AkTTH%ej zND0>^DNh&gKE5!S1GvE)e0RQmq%%XbjUDzKLcLkePl5RLj*&?MF(-e|M$u{15q0pw zQMdfy@W>ZXtx}`b>kcvr4;lY3Al9wmWeNBCq}R}B4a*e}b%JNy8iU#>a--n!)9$XV zdIdldZ3o*0RR6Q_Hdq)TKgVDkQhYFQP)sex34W#3PscDk<7noV+hyFnJhOS!y*=}) zm5{0D46|qjL6Jo~4!x*4MoNiSAcb_fp{M+r$Vbk$n{KRhaaXG0(O9CJ@KlYYllXM` z^Kbj88};iG%ikTh+qc8e|EKF#bNI*3_UPKb!DofnI! zSjw6zVM@beJ^821y5B#O6GhQ>fY5P{=ePW#fqdTCjoDUJb~a^c?`p?c7F6W%Lx?&% za-_60EgTGNRB{G)Mvii|G%dAU5N+s@UduLfLb86JGiSy~>QFRa+Rb*N<8iGAL7J?l zAtcMwx$b3_+6cx(1t#Q6ae_HfM`x=+s^hEVm|lytpxopilXz>-IrB=gdPtlMStHgD zQNpB+G0fG8rZoC@tX1hXUzB`!t%Nk0`l1peP^?#;&78S;%g<6{(s@fppkRK&dPG&5Zt}F+=A%p#Xj$S4TShi>4(254L_gLf{_}{zhQowvhN#NK zYg&5Uy^r*Gf_P{{|R5AA)a#oROZf3>WIH5Q} z-=2pT(BT)7&QckKVx6_ggiQFns2`~Bm!o48!(H(@+3YlbO2xJiacOwqHUU-ljdBXj~8fG#M*f8Mea zyFRZ<&nz*nj7K>4z)pZUM&*8D7UHVYaM+#|@e-CXP)><`F#E9#L9e84b=j8v_Km?7 z5m%wj%(uX#^}j>i>9~gkqy!iDQ-)uVAp7FE2KN(#1HfGa^ZE_Yp$F8=SaY&PWQw<= z15%D&^5ZRR3g`;(xi#!8GHJk)=KDdiO_g205oMr^caE-kjsb5?0EXAsCbZ;`!)iso zn)ul`P!al{|ce>9|4;r8=7m$uxK)mjRhz<09y5YMQ0?v+1a}0k^emim&sHt>kw!6#`gwQHbD@&kgX(Pu z*b9d&M~9J2S$P;EKn2xNAyA06Ks9R^x+P9rKVnW#pm&TGkc^Yah6zt-44jbRa<@tC z5#JzMf9EREmL89lE@#?%Q~sp^p%nWVO?Wo)=}R}!-}&T$zC9&wE=k?Yt!N4yA?y<~ z{j9b3snN}gt`A-klp$Ng2Z}DMKEhii%6CBqNKQMVe-t9B8vNrf0d%YfQg0 z5oRokRN*G68bfq;KSxnq!-~{5D4GoIQ_v#^H>qpZR*u}Ip0_Zf2g_Gu&usjM=~)E3 z{3B&Lu284k;qJJ0u6eU3!FEopH_}~uS3TLk-t-QE+C=eoUA!W3KY?`~DLD6;=s!5r zzw!(DaQ7NpBI7j5$topghj^TVJ8<7Sesb3nFzZIw2xtK3^XUv4It_Q_wIO;!xLAj0 zh0sV^A-Q;mTlda&B+s;<9fH=U0JJ9_!racOT9LJ~L8TITG&_h$WZ->E+U{2eWtQ27$Nn zM|~5t7jCu!GF!GQd-)Ue-x--nSoq(M-;9ju_xN}a+{)ZuHl=457 zdOnNWFP7Ty@zIhp@GaUwAb-XolCUDCBYXSl<;w|Sob=TxwJRZhhR1Z2(s7$1%ec{Z zr9Edv-b^$QLjJ@xIhx?ue(7Q|b$J|b4vYb?F(eHprp*orB;bMhbE*gyTy@63CNShb z92;wC87B{2F`@_NLq4LGEZ|K=Y&Znx?VJ+nRI5Hgjg*hC24P<;+!OjxiK3vjNA<&< zQ?hO%(D>)wL)U48%3ut7h@^3A64GH$wJ2fygQms-Dof?r_B2Zeroyg55rJ(Hld`oScln*)bNigwb&M*ju*M;i95|^OtCR6?0JMD> zW&Y4iU8$S9qrX}PN(riryJOc@!+WW%HdBk4z|tT^p>~T0XB4u~x;KSNp+!d1L8(n)-1(mA$+ z+AqHV9f$vUEOwPUI(st04W|Z#5XFpmH~i;aX>U$eB@@8cqt6(xg!~#`{XQvINRf#4 zOU)V@$ah#j3|Aq3D>m5WgCKUXiVvv1&7{%1As6LdbOaKfDO>gmD0R6#CUvJx^ZAXncXn@ZJFY`Wub=tGL5E{R{RKTf#QtTE6qt zc$e_T*0_)8#@gK$QC!iDplw~w4z<~(0%rTka&Wx)MZVCoOmQdFun)-k+P4kXS^p8_ zW!w?9&ak(IkiX`qU*fUdk2`eXS!I{nJf9U#oQtA0PqXpj13Lw4d01F{k`e`pT=STkA2C1&i;wG z85-OD-}K4)UY7iahOLlPGYwS^VZa#M9BSb&NDBo*mBhjT1VA`mnDsnrE7$Z*ia6iB zm}>!~NC>!3fPZM%x&VP_nM==q3xHm6JZ*5{b^GLe0@s8c{!AZA2s0%70h9nCy<3G_ z{1D3+%Nna6#x=J$mQ35P-Wz{dQG?yS2c@gZBV`2Vb!q~oFCI4|k$+T$W6nuP2FlU%*UrJ^UD3Ts&= z2B&KAGOxp%F|NEvp`9K;-5X3MWY&QURq_}6h2uB#jnr8(4Gp$E8 z4fQb++(Up_fUIMSsRgQwl+B6v(J3bQa2z z8yKL!xL^(M!v;>8aiTN~+$`KA&})qgH!a|j&#!LX;cn*t6pp}{9E zqzd~Xnb&(qz+Tl$7Ut6$q+8KHEc8Cfzo3WCgiOC>F|^{7W?v*Sv_6S$n1ZpaWe~X| z>xVVOl%8_7V7O;a9k?);-4ln=!&j0z=kasY4a&njdCi0z# z|MLH@AfrfG#}--v-Dhg5s&QUnu_|Us&AVD<>B*ER4o0CYSs9#!AuIc2A$@fM+M0-$ z*3MrXoRD_2#hxe+5zU6g=T{DXz;Pzdra%S??PJH4`}7;{_j5eq^ZNJ+vytSy#BCZ*4@)5 zXnXSPk4@L=bE>=}%DBR&{?k_xU*|EjsAuEna)NgX9n9!X5RbBcVdJvv`IrQk-6Ah+ zaREY#^j$Ov<1f-^kSesr8Q==s=>&mRgU~#qv8kWK-OBN@gOv_fy0F+9m@wYeiR3yT zU=zHL+^9fJpR0BJ^}Iarz>mVdDjtBM0y6rz*sew_4&HPV24KTwB}r61BU9^VaX&N~ zfw*o*8BFo(vLeJTEVy+mt9;FrITc{KNf5&GZaJNlDQgkcUxZBvtxoN7u$3VH_)K3r zXg_l2s&E`o?j;8yXNX=E(|G1aqLG8YrN))13GIgetEU zbx$;X>kgx>F$k$6()Kx;sNNQp`%2sZq{33Fb4!0JxvV^VD&-gbGgzW}qJWVW;8AjN zus(hBCZ4BKmdgVvkWsK4*@}>Lrvb7nXZ5V2)9n=|^8Tfn{+Dg64MwJLF?+a1$(d0lHSiSD z0O>Ql0FI2=B7i~P;Cm5nPLL*vVV2L)@YP!v!0>mgT~*h}<{~(+*j5YrX{MR^;1@X$S3ntwUivQ>~Y#eXZ1Sg>iizo zP#JWOZ@=PvaF6~5_cgkJrdq#mCg|^$?tf8;`%6Op3-3oMUC91ZT3xQKp-B11U^Oay zQ)L|`IVN;5bNm8wK$#$>56!qdXv(IEYs57zFED93Cc*1=DC5>@om{t z1{ag>=jS_!9&9!8y&v6A{Qg$fO9?L++2 zYn~-NZ48bpl1*eo-IRMEIHZ_SP5LAryvlT8)K`-;{ zSxk+)4aGF^=vx>M&%&8U5U%$zm-RYXeK>MC^x}>pMR9Lt`m`x1mz?8H=7)`3J|pNs z5P1A3TKPeh+(mSsq)M=nYn$%i54aoQG%eX8QN9ZhMUdW`BcUq#C1zJXp7wO-H^9&b zvm|gZ!iG;_$PCB?+#NMbyFu7OJQ?F7aE3lB%DN=*{&XVIpgMNolPfou*v71%W0LwC z0Ci*)YmN?SlCVt81N+Dx%+-7%zTLB{|ILS0D&a9ushpA{UQX0PST;Y(j`ZdRaF`{2 z48c5Br8o(hpgCN$>=`BxHnCv73xwjzbE8o9EvXNE=+qY-iT9I$)I9PTNBZR>v7SC& z{_}6U`y9*IFoxe==Lz2_@V_)>|GI>PY;8=;P5(=TDQ;Z0j~_YYYgbhOS)liiU?AGe zzz_=50?ce_nH4j7N>LyTTx^c)9|Y1iEoUsm(eu^IqN zg;A`qM86j(1GSm@Ld`(z8d~%<9L8RfMFhcYEY4IcQ&4|Kzd%NNiphGhWN&P;d9$<{ zu)Fd%_q@wsB!?5)4zqsGEqj`*Kk7e4qqU((8(KB^&_#yxF^0lxKi7(|`OwM9qDjl< zjk|2qH|M*=Et=;=>s?a_LdptSY zuI+f^Y819#IKlHX{QjL>0;dE89(jCZCL895w1FgqG!YsL9)8uq99@{sRV2LcJ84ZBuq44fMeGpt zty4C?z)gK>0s1S|Z^?LG$TJx9MqYq_Z=zd#wo;k6NWDBe%{E z@14MIzt=)im~$V93P^YlAAuB_D~V!3q9%(e0KBKnVFHDf#-d4w@=iVA|2ydw=(XVY z6sN)<2_o;rdE~a|-8Tifozwlp%5YK$MvC^Q8@YZNEE*k8N1tW8rpwLHpjH4LCCR-F z=5gx?gbg2d&<7lXK96KwJwI_7_c7mUu&glsC=&{{g?VaRneA=iFkpXYOu_8z^6pP| zbcEkriV}C(@|RY)@R^(E>hP$9Wdl2VR@C?8xFs9rA{vM#V719j*(^AYl&e8GW(Zge zIKnHJ!tU|r_822ptewpq)0?KSOwf5v{eERQw%q{U@h($)n>175NwaVu3SVU>%Je>hvdk5$c$%RzE-$6=)^e?kM}@It2b!DHNQgqPL#X zX}WGmy@#IGCn>8jXJA(9I2+^zYYkz3G zu_2Vzmh@q<7Sh=VZr&j>QeKwYT>3|;1G1lm^5+9K=jM zos~nHh;g%m-RxLoYkg=<68Tu?!|T*#68cjxed@1O=FZJt)}xNMM<4@z9NMwHP1lsa zP^a|f`ZSQKCnTyO&5_ussr5BbRgl=f#4u?j_80**UOKB)FPefo^5-=i}nU?o};){ z5=22cLQh-Jr@{FcM%-a?A!hXm-dZwrB$WEdFl1!Bt^ZnOpCeuD^Y$r^r8HNJj$IA^ zOu28Fx;w2$?!aoz8`0cSeci-c_R9ziSH(@NJ{7m-Ig1+Dj>A}iAc8_)VRk$;^}uRj zJjpOM^r7x(Xl*RV=_k8t&|d5|^92a%h;7`5t^6}$EA@O83ZsqvL)ww$(|WO2$_=e< z)7)$%t5m**=&C8^Z!%_OFw9SMGqbM95C{u$wM)JP`^b0S@)j8sYsTjQ$}Zv*SgoqL zJ6pGxE*ynfX%*%hTnkMRCY9NDK9u(cFiM+0nH&6yC?2c4d`jCxyD*sx&F5n2&Y{Pb z7MM#r$q(j{d&^4ioOorJFY-f9eHi}oCH&fR4=GmO=kYhy7U|J0XQ1kIvBgr z0sW<%|NYpvpZb3uGq?S3C%L}0l#Ra&|LAw&$NIOE5^{fIOPpiBFJ*c7kT0SX$wQx~ zGCJ+am!=fP##^>6PJ^V!r>>qK|`gU3~{EkfXw>cB)zePvU zSl{SBi*RuKKd17BznbCxsDc_gA|WIZP;Q1SfFbJU5}V8x8cFU=ARelyVUn+}6rVgR?lnZ=SWq@nP@5SsPznxv z)37qmqjJmLArLw$+vnV+4J=*cgjSsAYQTV`8E({#0o7UewRCwyrfB3IKX;Yh-hE>y z4<457ar8fYc`Unhd&OGkZur0%dpQtM4-}}8)`U%mzPp%d@Ti{950aNRk=M=Ce57~c zPEoIOnK?j#)ac*IM!wG^z_6}v8t&2d7#+j@V%X~@JL|dkyqL8+dC8OcjktY>83@~zN-eF6BU|y17Y;^dFv0~}~JTaf123*T;$@>VUPCRb5g_yNBh?)mn zhjQA!@taNf6bg73$w+?#zIiwio=81B+W(&9ESG;xgz{*oJYf%=THzgXj95NgwqBQ< z(#eEkZ1yR#uzGNA+Tav>lyyqNHS?@9HFjhWaU(-qIu9|FmW=5B=ddJoy_9F1?iyRz zmE;`80UkwGQBXAJqJljTo6>@odQ@4)O%aqq+n=O?C@2P+(Ne^~kI-7qz}}jW_3*Ty zQ|UAerphnFV&@HsNv9N_LI`KBHC_26jD;v+T?-G^SJU7cxCCK9_zuiR2r`+j-8+V3CNkXKZ~s-}Ici zbGVfGe1Cgt2H^d^r8ip^BWb0_uZy6WKuzM}PF#Rp)9Fp|1KL4zu0}JgfbT%_Ta0&j zQH_ih^1&FXMXqZgVxR}?*#d?Us4c;hdDMiwcDe369TylPv)5@)Gv`7`)h&A5}C3} ziY>?MyGuRST{QX!gB_|4G(8JkMynrI81Is$XfbuMRBN^ED~oi>#kVN@&2=6pHm34h z|DZ8mo*!1|Ow*#Y>bj;?y2SeuHztpokjyz^CCR|}H$rbGv0{MYl$G9;r?{T$$dS4v}PxzY-;Szk!F}QaZs;-tSf04OC4n@Q9`vIDh^I+ zI5yEou|Q%Yz!jYIhbr9Xll=;UzS=bamdkg;Gso~aaoNl{SCsi(=f4wN2skE{C#B$p zzt{zsrc>5Tt~H_MDTQKd?%1SEaWvjYh~R}Y$fh1{fMSWr6S1eoJx@Oqd(OU;d^*vh zl@y?Ij|uMdE84O+OpY_3mm>*#e#YB}kHu+0cOiKyn<%?(qv>?YO(k@-vgtKhLm4gx-95%YcuRmSCCt;)GuBh7e!11Y31-wBO1&Iqj4KY}k#3Z0V{W zDXT-rL<#pYP$tr;q1ovU0U#sre1GW7e7_ht4&l3|F&W1r{zPpOIcWN90ILseZWcI> z5dfonBfTG$-!IV7;A0t&Aq99egagQzBHzGIFwJfJIz(Ge(Yvx8U=&#_(;5fhtT2VN zg=p3K_cgq-PEBYElJsT2ZGuAYSZqOyH@#PIP=CPp5MKduJN(j9l&XreKgym#$$^+w znMwS8oRyX(E9k+Cd0=079xI`r5i5I{B$*n`!Ntj#JFs15d^n zH09oWM9JOkl8w|+Z@tOP+ViNU7N7iSy}jA(gItR8q|8s|{ve93pu~nwl@LReh`&&l z#msy`DCQiDaj){0sIYQGblgyGYc6A(Xe-6z96gj~bD|p~8(jhnp`VV0(BB&oBYO{r z$J~Tp4ajvNA(^Jny#Fq?{knzVG$FZve3OIEP^o)-o5U+C|5A}zB1s0NI03dL6Nb)l z@XiFRy4yYoiH}nbHOVJ64DcM1ARo1fW`NAzZv7)&eVa6y&q?i-RI;dKOAcnkXjr$) z9^{=nq$ybBQC;=g2ngfcXJOoyC)!h;cT?|I9V8^@$ZOXFt*IUnRhj^Ej0 z$MgWmFLf*Ud5>s<1nTmaBTz3#md}QTKPr>n;y5u=3~K#}YcGR;K|TMdVl;}h3^CtT zY!c%CUB&*&j(e->d^@qD`^eVmC&(y@L*~T>71LPonkmJ-{%C9nYARNgR}vVoU>gTj zZN^HsioJnzyDB=Iir8AifKf^_r^~t#E4$)o-=v1;l%C3td2-Kw;<(~4eLmjq{t5UD z;0!`RJ=Ri*?>7i8Y9}_dNzbbQFPJ2^wLe+Hn2b!Weh~Q9p`lt6Fx~g8O)!C`kpKJU z=m(z9D3ArCs&NGa@SiNu{??+aMV&^g-%F~kCe6^6mU;7LCzTu_{(nM@SJ=oIb=8ey zDJNyJ^zBA#?hmK-+qOJ%mt@iEro!&7z0F)?FfwJq+UX8{h^IFyviboGcUc*YFfqRkc_?B*dDTy{qin`g50j9GpU9 z@G(qejY(eS-G!{RtXBu<6rs$lF?1OU?~>T`(5;nLY&h$o`(FgRv%;)So0NP*Zg>f{ zR>4^&WIZ#w(pRmNtP|Hg)4L3@WFq1eh-7v5WN1Seza5be3hG!NI+LP1 z=hV$yDkhtT2Zh+&?xG??8N4E{PGU81<|Fmv>n9CpL&W4?=*3!}wk<;Pw)*~*DSuJU z>t772s(Doj)5vYULmVS!;?gf(!Diy}I(Y@d3brfRwtpyh<)H88BQM;=bD+8$aPI?l z@=YC3KltVC{ZPMw_kREa{tCL!JOUh%_Y5KAx6KM72SpG{ z7G(engvdnOP_|F8P1ysy=b3()dke!OY{n}_Z3f99$r}_Lr@gap4*O-kXLS1yibv7U7 zfvM0z!py$APP@x%Og8(Zc|>eKSLg!xPQLSz`Nh-|> zt+p|H(H=UCRmeAiIGb!1(3nT4$&FG(Y(VM|b1M&>)B{A465m7Q3}g^B2!3KDex%_b zX}-2947e>U$Bs7~oa3BBjhh2RspXurd+(Nq7$IA^k3m?roqaxrRj!EYS(})9El6tI zvs#B(8!fWxLq$!}Q3;RgBTAitV`XrLX&|BqO`Luv_qn|}PJ)0z*qhRs2Zyo>E44aJN* z_aq*jwBN6BrMNt)w5tv1K>9yBX+u1%fDC-LT+{lujJu*^bi7svL)kysTlRoLxvyca zj48qyKC%$>hx&9o5l0|`E78+j}XbSgDz zg-&uuW}Y@|*0wkU6E!O6M?{V*2kC2!*(%j8p2U*dEwNcfm>LdKMGFjCSet=L&KECG zyDihAEwhfS$-1WzHdsPxdh$~vr=XY;*pqnry`JXSA?6H=l;$~atPFndAQTzF{^Dje z!i0vzXcNa7wZg%|i}dO@Te>x#Zp>(8xlGZ_9`CKzVT|02-9t;rv`Cr?SyZ-*z%P$- zDVLqIVyBTUJ8#gLUu)p#ZrPqdq$@H2fI#`+rm%0+K`BU8zE&SZ;yx7BEP|<$KLCli zC@>tqFU^QB@^0tylgi`OUxTTwaCff7(ljqLaUX2kof{y+&?&j0Rz1M*fJN}2C)oHl zeD5;SFS|$3m?LWN*pp=oG&+=EjNd(ntEnb*3Y+5HRi>9NIRo2a6%}W+FpbQ2yM;)C zjLV$#5jtU8IM0o&zjh63p^@=g8;2CRi~BXuIHd|#m#+*8Ww=iYeW1oaE(-&5clgaCYJ zz(0TA!?piOcsM(mTm3i6BaD9@i1nN4Oos&kApYA~0Ru-T2Yo{)AzLe}Z&Qf>8no(E zomN6}MfT00wn7ZxM<(n})QckE>oL%>^d}d!QsLKvmtSZjrm6_Bl4eDH%Nc1^qQgE1 zvCJ|r>13amlIwh0NsA8MGM}Gb-?T!lQ};YII(pmheDc1!bHDQL&dB-ty!0gGl=1L` zofq`$YZ&QQgv!dt;@&VCtP^eqB%TG7vT2rQqp4lQ!R0-^z`@&05{H$?;xaEl!83NB zy2*V$!JRHgtduB}bkfZ|vTw{iGxzVP%>(fth)h-jw#ZP08nZI?7NM9Nr*an;oYz#H zq8lMedPuP*r3VrEE*bOVg(KL&8yR+Titb^z64PI#Q|S)6MW;dc^*h zgNv7s1vLy9?{}T8t4i9TVrBN$^&!p>qt$R&c|KlP45(0(yk7rfp?pW0yhw)eS(}H&VL+|Fuq2AY~CS)n!P!#J#nK)4}^J7<`gp7%?kfD^~?BG!B_ z$&n+HKddTT-(YW}4@IG(1FSmx+%2h}mwkvSl)oVq!%+{0B7TL%6(KX?<-#O!sW zzjh7);sBI-yDeGistnQ%Joc$IM^as8ZXdO}n7d6*TxnY2!^9%8N8Qmu8orISBxRwG zlCxl`P;^d)LQM)~MCoU3{q9V5b?HlH-$epOjzhV6!3a)?2oZgWiloM2{#X>QO@~jv z7rQvm0#+dsGSnP{2bsA0FEH~gNP#(Wl9_Oii9f*(Md}NZZSn1z2Z_DI3!1prp2`r4}!%TTZzq$%^oJc zo(utU{rZA*yLS$L!n7nV-YYWtsPt@uISJP=s6Wq!(edF#@uWYTfXj2ug~iMP9F0

>i+u~;WeK)C`6t%GrV`LpbYK=E09fQJa7tVOBJN)?B6_U# z*`A3KNTH8DUdHO?D}nX1KjCs`IMMP?S9sG&wB2NS@vR&(II^6KBvlir@lv6Bz5`^h z>?4{?V{wbZ#OSErSVnsFd=T8n>9h%Gxen33i>dD_b{jW5^Ulg*zBtCX#1CDVA*mN# z?0s3F@F`LG_*TvoxZKoU?_aLb*tw}eEi^=nq8FnYS^*OC1%%4a{6wY=KxGF#lOR5V z_AwRkM$|iliK~S$J`WLRV-_B=32V?2a(dd|(BL#Bxu=RSAifCz1e{#S!mge*TdnAN zv~3=SU(E@S(VGii3i}Y zLJ7r7j$pmDWr*0&+k!xPvl{E$!jRKg3G{*@%U1QhD(}A%D2LY>I;8?MdQJ>dy$_7?KB#zS^g4;IrwWp9QvZEnbh_&N5-b-bE zC%M+Khe`+W=;=;k{Zpb{d^n1b!%bqsaz>#j?Q6*LZnERDFEnxy(#_bPEL0p)zWU>; z<9fTt3o}T6#eT!xge8k!-CEJ{q^CY*Ata^Dn{>6SLk1@TBJjwH5#=l0D-WJmzRa4l zMV)Il-Kra=-kS5C8sluExN5LuQTMR}#a+9_*~>2aSjfQgMp2%qx z?ViGV<%QipE{D5%7RAIQ-R}dlt|#Z5LEZPLC9?RV#hTA-J*F@FF0Qy3=Zv4z<-||e zT7@5h1X9Q^Yv2nQn&KkPVjAwc8tfB~P(?-xk3ci#io&#ij5%y|Qs+WoJ+mU}jRlJ#BbCZa8*baUF;Fetzt; z_+ho+4S}N)qKn90c0m(Gh_tqoq^#e%k@dBcfV_bBF;YeZ1RR1ZA0Sr<(+6n>W$9A1 zl;@W2WCv732y~irCClUz3Y1w!zwx&Om6}~ZZK5pJsZ46gBgWtp#Xf>G` zr&lRVZ`4{}n2*|RfWVGo6z|d^lEzO0l*$@UHhU8mO?TG-4V6#|VS3+Z84&(>szxmYialW7Kx^E^eEs5Gc%T%J85HW!~! zH#^l{VJ1^Z{9(zvs#JH`vQSqsT%Tci38tTi%iTARkar5MY)#%=@|zc4swl3EKoN?^ zIg?~2vxOH#*==#98CH>3w8urFL`+pf5R(?spglfdq)qvy&D+mC?xR>`P|5PJ<{*|w z>xELU7$1(53+Hwl8FC^DPwHt@x;z-IdOX#VPd4mafk^uS*9d;R&Bgl;xRn%fT(3*l z_gu!IULg8(2#mdNnrzRl!ELNbKRE4z%q<0etz_W)n2rk(jKzG3v#Fyps!^6La02KDQ91qPM#{jA=ls<`G*jTzw?vUFn13}w> z>m&J?QL7I{`@zE6f#k(HG69SWB+*nJa2nzIYv_}|T~dB%<|F&u(0g^b<9rl0CvN@y zXRKg4)QF(3J!QzRqI;|O_hN9XnOx~B;RPK4(h_}*0~ zgFxfduTH2xkY9uWT>^ef8h&Ev1-AD7xQ6MhvBfgDQ&)BgUAFz%XUb1{q4r2j8-NCY zXoqf$V@Q-zJj%+?TXu77=xX$#(4Jl`Lki0bR}#<7%T<5{PhW)ka17_WL^0$NPg25o zqn|Hn!|jt^u#HaA4}Ol(w_m~3Qy$pI^ds0TMyw;ACPApaPLiNEvcXdEag~G!1R^~7)nT}~%q0ZcAaNqK zOwT_d85liHh<8+5b(B=#A@3vOi13+C&H40t$FWAltcX6(fnV_jUHy%xQjH#os``d@ z7~eb<(f?RC{!u*sQajfFL05fc8TB94X%izB<{fU4Liztym#XFZa7sDBEum0r18NRYgCP{4A@4w`Dq3zy&dh2pz z_5FGq<^h=Ac>vJ-9+W^oex^k!Ty{rb5_qP^>OuYqZ%+Wu_ci;gAq*`LT%T1uJ4M*& znRB@RsMS+oKm>sMN`BZ^T&h!P>RVAX((KcAeQ85ewmHAXj)5W z?K7p2;gX`m@=;Z()+-6c3Geop3m!0 z$Cmn%97Q#zQ%op18qLf@rl@McluCrFCl}xgf&)F0yt20*!$@%#rME^Xvo9(iRasER z=`R2PVN9ax(v(bDwx&qgd{a#oo{kpdoqNeO2l7`jgr$hD7Zl3T=Oxl?K(T zC)uT?ykZXXevZtK&nRr$z7amOiw9O`2rJ^b(7ga)IT+Uu)DyMBu((<;(JKuV$1PWx zaRjH>;F13EkuARGeIPa;6+tsXlOkSYa+-tGX`YN6x{XMW zhQ@2=J{alLd>F~-B6ky$`+9DT5biQyG|+W7j>~noQ-qZ+dbS+}u%~Iq(3Wt7(#&K% zES^U&EiqKq>BnOg7LU=NqE6ux6r@VSj^#T(_apLv>%H!K@cS3{lG%{!=m=X!S^d7JD zsRMmHAcrv)kFL5TWPir5zts5s?QxtBL^gqMs!7k{FvAY+ps?+x+eoC>ha^a=&aJ|%WyWjmMs)S6`pZrf@l zc70tJI36W-SkeNvtsY;}uCfV;eTv%=6l0+aq*S5{Zq&c*HH~ zqs250tK<2|1ejH9f+VE`HS-4gH{YKrH6(iF*}`H?z3Fi|zIT^_sn`r1vk6U(#Eho` zLUp?W!um#16qMGdDzo%;A#B`|*l)>ul)=3P%6olQW-6)P|=nRrDmFId0R0gsp zDL6)9)?MDA_mSzt>O$%QS9~NJuP}{e+?Lm1$&N}FKSBX!R9c=9`9g}!ANOD zvcEIU1XQ-Jjs`_pXj0PE9S)LK*7nYSUF=JCU6N=S4`fhd)6B$1L2FaHk=Lr*x2ue1 zvh=jLtZ+}5+9s2v3g!$uq!&x{|)~QSnNL4f!mNAiuFYcqW6H+ZuiWtLgm8?fh#ppGB!?F%uj1=czaC z3j}{QVe}C)Qhq5CQd<;bCY+K!((Wk=-^n9Ccr+Nr0kIH1&Ro+x%tIFUq`o+76j;~U zz3cq$ED6$}gHCa;wl-M60LzcRb*;AZL_FI_111=c-Mx4yPuon<6%O8LjOmR6ZlWf$ zNGNyuTPacJXGbcMc-Vffj?`;iqrKjMkX3DJoF>Eecaw-si7>Y3@gCwomN{F=9yj(7 zqI`rQ;1TXA97z|YPdq9UBaH6U`tDknPrPT1qG zypf6WrvOOwK88#fbmg}FT$3p2B1D4Aq6pGBmS51h4rF$i*;mY!q1*>T7xt+JIMIj+WUhZxfNY$L#DnZKr5m z;cGv9n?LwOA3iTlpc>KCFU`xN9};;FJI?1FX~yMG|D0Qe01dlAf`qE@QBG=gtSBjbL*|A`Ez7)Sf| z{F}IKkpBO==l?1v|5;3m)wLXOHPHC%)h(A2Ol^bMW!4&4ST<}Nkn6yMs@CrPO$;Z; zC&9%>Om;k?m$qaW_5mm&L#O_lNN~K|j)b0i|jQ#@g?*%nSJ_jKH0^<*M zRu%Y2rX>|aR3ATjK5sf-x0*lOF>?M=`+quAB1zGb&&83I06dsH+D9g(N$@mfwV<>k zyOK56PJ+~S_y=^tFj8CfQ6}1EbmCg=V-Lkat~C#*r#bPDPjwF5X#{owf*APLWVpAH zhxec#b*Q5#AouGJ1Ig!}Alfym%vn-0ZhC`g;nf$hO2ocS6Vscqj>c72=__l&hiBH_ zhPru0s+8y-8@N_og{ z(O3q|z&}{oo(g83y3u0l zZnzS2&JJ@P+zgi#7x{ZAJ%#O{JU3eEK;67zim}k-oCcPA-cGr4`Zo?%!=Y9-Ggsu>0YmhO`!(Q%g)+ z)kMQG8L6-g_I)^PXS5G?vUd;oa0o27zFEt6K#xvo5r^I0mdb;;I}#y{x3rkN{o=c| z`@i1u1b2HHXu1BG03(BPahOpDaC?#1S2et1?*v!U{t!XmU~RtW&dzI;!r8CWw?P=a zIsD=;*e`s;OtBT)CduOQ|#oYo|x%Ap}^ zpH8{DD3e1&q163v9g&3FIXkCYla*e4`4X8g>TP@a#Ou+FK57oNlWbd?tO1r&6Ioh6xKlgM` zk@kmWZ}81a&Ybeh6iB8poB^poiAG06QcNp#Mf%dJqRJEzkq7t%JSj_1TR2<1(!9H; zpJSh?`^OVW3<>x>xf4$|1x$?*qGs8=+7eBt7vvfAcXoIgvzR$}?Ral<<8MQ+h-kYM z0>1u5Z$z;X1X5R62Il^JAu7T0l2*7{4cS9NU4dnFqP&FNQefd)7cPXZ8S*|?wWN5p z1Hl7!h`D@nE2H`W8&emu09@QVz>{kx*hp{>45 zrYGant6Ejc>f5@>2N*}E4CAu~O47bDg9jX#=)Eb5UyN~}{BfX`SW1@V$+MF2(MTz< z0`RAj-vNYRxhnn=l`45a_6L0~aKCTD_BT5be_|1Tau9z45PuR7ejKUMv$kZfZfMrqW@(fk7appE<&;UoLXKI<;4^8Uz%a1CS)h`%Kh0;l0XT-{5jz zcytE@7HB`BrEeH;ai@;DUpS>hFlusXaJ*yS>od{@!m8n;_u5?2)cU5sY8w_R5$Qh? zJaS;E5Ev2wTDt1^@@4wri2}B*Zs07a6&C>(atNYsO>39o9APxl)$(^(ikYw|5V!Cf zr!0IrXKTyr`IyA{oY*2UYU$Q6Uv`z}S1ovE1`1ss6)?Lt3F0iPx*7@$7-OmP9uVX2 zvf{BRJ9J%TM!J7IEfQcE)X=Ooez(cUn-fvx%;Zx;>hTcriVA#Ws0WURV++kl&PVj4pm_${7=OR%-8^`* zc;n5u$+P!`3A6In5pg~v=N5@mS95A8Nla414IxjzXXQ)+AJt|HwDW--reGVAozYKhvj;loql~O zBz;dxOrB$qcb^r?oc9LBpE-`)(ZjN`fQMf7D3zqM5wJAiNB*XbA<} zm@orwWJOuhHNkPZHnQbloF?W8WQN3z$FE8(*r_dUVskbN-NZFW3�qY6!ac*pu~W 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%0Am}8Hd{{dIiukHe6vwyCFZ&4by6j^X&)uE!XBzR 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 Date: Mon, 25 Apr 2022 10:58:15 +0545 Subject: [PATCH 012/112] changed according to java convention --- .../cps/score/CPSTreasury/CPSTreasury.java | 236 +++++++++--------- 1 file changed, 122 insertions(+), 114 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/CPSTreasury.java index 68e88a64..57af3a50 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/CPSTreasury.java @@ -1,19 +1,3 @@ -/* - * Copyright 2020 ICONLOOP Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package community.icon.cps.score.CPSTreasury; import community.icon.cps.score.CPSTreasury.db.ProposalData; @@ -26,15 +10,12 @@ import scorex.util.ArrayList; import java.math.BigInteger; -import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import community.icon.cps.score.CPSTreasury.utils.consts; public class CPSTreasury extends ProposalData{ - private final String name; - private final String symbol; private static final String TAG = "CPS_Treasury"; private static final String PROPOSAL_DB_PREFIX = "proposal"; @@ -67,122 +48,110 @@ public class CPSTreasury extends ProposalData{ private static final String COMPLETED = "completed"; - private static final VarDB id = Context.newVarDB(ID, String.class); - private static final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); - private static final DictDB proposalsKeyListIndex = Context.newDictDB(PROPOSALS_KEY_LIST_INDEX, Integer.class); - private static final DictDB fundRecord = Context.newDictDB(FUND_RECORD, BigInteger.class); - private static final BranchDB> installmentFundRecord = Context.newBranchDB(INSTALLMENT_FUND_RECORD, BigInteger.class); + private final VarDB id = Context.newVarDB(ID, String.class); + private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); + private final DictDB proposalsKeyListIndex = Context.newDictDB(PROPOSALS_KEY_LIST_INDEX, Integer.class); + private final DictDB fundRecord = Context.newDictDB(FUND_RECORD, BigInteger.class); + private final BranchDB> installmentFundRecord = Context.newBranchDB(INSTALLMENT_FUND_RECORD, BigInteger.class); - private static final VarDB

cpfTreasuryScore = Context.newVarDB(CPF_TREASURY_SCORE, Address.class); - private static final VarDB
cpsScore = Context.newVarDB(CPS_SCORE, Address.class); - private static final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); + private final VarDB
cpfTreasuryScore = Context.newVarDB(CPF_TREASURY_SCORE, Address.class); + private final VarDB
cpsScore = Context.newVarDB(CPS_SCORE, Address.class); + private final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); - public CPSTreasury(String name, String symbol){ - this.name=name; - this.symbol=symbol; + public CPSTreasury(){ } @External(readonly = true) public String name(){ - return this.name; - } - - @External(readonly = true) - public String symbol(){ - return this.symbol; + return TAG; } - @Payable public void fallback(){ Context.revert(TAG + ": ICX can only be send by CPF Treasury Score"); } - private void set_id(String _val){ + private void setId(String _val){ id.set(_val); } - private String get_id(){ + private String getId(){ return id.get(); } - private String proposal_prefix(String _proposal_key){ + private String proposalPrefix(String _proposal_key){ return PROPOSAL_DB_PREFIX + "|" + id.get() + "|" + _proposal_key; } - private Boolean _proposal_exists(String _ipfs_key){ + private Boolean proposalExists(String _ipfs_key){ return proposalsKeyListIndex.getOrDefault(_ipfs_key, null) != null; } - private void _validate_admins(){ - Context.require((Boolean) Context.call(cpsScore.get(), "is_admin", Context.getCaller()), + private void validateAdmins(){ + Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "is_admin", Context.getCaller()); + Context.require(isAdmin, TAG + ": Only admins can call this method"); } - private void _validate_owner(){ - Context.require(Context.getCaller().equals(Context.getOwner()), - TAG + ": Only owner can call this method"); - } - - private void _validate_owner_score(Address _score){ - _validate_owner(); + private void validateAdminScore(Address _score){ + validateAdmins(); Context.require(_score.isContract(), TAG + "Target " + _score + " is not a score."); } - private void _validate_cps_score(){ + private void validateCpsScore(){ Context.require(Context.getCaller().equals(cpsScore.get()), TAG + ": Only CPS score " + cpsScore.get() + " can send fund using this method."); } - private void _validate_cpf_treasury_score(){ + private void validateCpfTreasuryScore(){ Context.require(Context.getCaller().equals(cpfTreasuryScore.get()), TAG + ": Only CPF Treasury score " + cpfTreasuryScore.get() + " can send fund using this method."); } - private void _add_record(ProposalData.ProposalAttributes _proposal){ + private void addRecord(ProposalData.ProposalAttributes _proposal){ ProposalData proposalData = new ProposalData(); String ipfs_hash = _proposal.ipfs_hash; - Context.require(!_proposal_exists(ipfs_hash), TAG + ": Already have this project"); + Context.require(!proposalExists(ipfs_hash), TAG + ": Already have this project"); proposalsKeys.add(ipfs_hash); proposalData.addDataToProposalDB(_proposal, ipfs_hash); proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); } - private Map _get_projects(String _proposal_key){ + private Map getProjects(String _proposal_key){ ProposalData proposalData = new ProposalData(); return proposalData.getDataFromProposalDB(_proposal_key); } @External - public void set_cps_score(Address _score){ - _validate_owner_score(_score); + public void setCpsScore(Address _score){ + validateAdminScore(_score); cpsScore.set(_score); } @External(readonly = true) - public Address get_cps_score(){ + public Address getCpsScore(){ return cpsScore.get(); } @External - public void set_cpf_treasury_score(Address _score){ - _validate_owner_score(_score); + public void setCpfTreasuryScore(Address _score){ + validateAdminScore(_score); cpfTreasuryScore.set(_score); } @External(readonly = true) - public Address get_cpf_treasury_score(){ + public Address getCpfTreasuryScore(){ return cpfTreasuryScore.get(); } @External - public void set_bnUSD_score(Address _score){ - _validate_owner_score(_score); + public void setBnUSDScore(Address _score){ + validateAdminScore(_score); balancedDollar.set(_score); } @External - public Address get_bnUSD_score(){ + public Address getBnUSDScore(){ return balancedDollar.get(); } @@ -287,8 +256,8 @@ public Address get_bnUSD_score(){ ); } - private void _deposit_proposal_fund(ProposalData.ProposalAttributes _proposals, BigInteger _value){ - _add_record(_proposals); + private void depositProposalFund(ProposalData.ProposalAttributes _proposals, BigInteger _value){ + addRecord(_proposals); ProposalFundDeposited(_proposals.ipfs_hash, "Received " + _proposals.ipfs_hash + " " + _value + " " + consts.bnUSD + " fund from CPF"); } @@ -298,8 +267,8 @@ private void _deposit_proposal_fund(ProposalData.ProposalAttributes _proposals, public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, BigInteger _added_sponsor_reward, int _added_installment_count){ ProposalData proposalData = new ProposalData(); - Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS hash."); - String proposalPrefix = proposal_prefix(_ipfs_key); + Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS hash."); + String proposalPrefix = proposalPrefix(_ipfs_key); Map proposalDetails = proposalData.getDataFromProposalDB(proposalPrefix); BigInteger totalBudget = (BigInteger) proposalDetails.get(consts.TOTAL_BUDGET); BigInteger sponsorReward = (BigInteger) proposalDetails.get(consts.SPONSORS_REWARDS); @@ -310,13 +279,13 @@ public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, Big int sponsorRewardCount = (int) proposalDetails.get(consts.SPONSOR_REWARD_COUNT); String flag = (String) proposalDetails.get(consts.TOKEN); - ProposalData.totalBudget.at(proposalPrefix).set(totalBudget.add(_added_budget)); - ProposalData.sponsorReward.at(proposalPrefix).set(sponsorReward.add(_added_sponsor_reward)); - ProposalData.projectDuration.at(proposalPrefix).set(totalDuration + _added_installment_count); - ProposalData.remainingAmount.at(proposalPrefix).set(remainingAmount.add(_added_budget)); - ProposalData.sponsorRemainingAmount.at(proposalPrefix).set(sponsorRemainingAmount.add(_added_sponsor_reward)); - ProposalData.installmentCount.at(proposalPrefix).set(installmentCount + _added_installment_count); - ProposalData.sponsorRewardCount.at(proposalPrefix).set(sponsorRewardCount + _added_installment_count); + setTotalBudget(proposalPrefix, totalBudget.add(_added_budget)); + setSponsorReward(proposalPrefix, sponsorReward.add(_added_sponsor_reward)); + setProjectDuration(proposalPrefix, totalDuration + _added_installment_count); + setRemainingAmount(proposalPrefix, remainingAmount.add(_added_budget)); + setSponsorRemainingAmount(proposalPrefix, sponsorRemainingAmount.add(_added_sponsor_reward)); + setInstallmentCount(proposalPrefix, installmentCount + _added_installment_count); + setSponsorRewardCount(proposalPrefix, sponsorRewardCount+ _added_installment_count); ProposalFundDeposited(_ipfs_key, _ipfs_key + ": Added Budget: " + _added_budget + " " + flag + "and Added time: " + _added_installment_count + " Successfully"); @@ -324,17 +293,21 @@ public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, Big @External public void send_installment_to_contributor(String _ipfs_key){ - _validate_cps_score(); - Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS Hash."); + validateCpsScore(); + Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); BigInteger installmentAmount = BigInteger.ZERO; - ProposalData proposalData = new ProposalData(); - String prefix = proposal_prefix(_ipfs_key); - - int installmentCount = ProposalData.installmentCount.at(prefix).getOrDefault(0); - BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger remainingAmount = ProposalData.remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); - Address contributorAddress = ProposalData.contributorAddress.at(prefix).get(); - String flag = ProposalData.token.at(prefix).get(); + String prefix = proposalPrefix(_ipfs_key); + Map proposalData = getDataFromProposalDB(prefix); +// int installmentCount = ProposalData.installmentCount.at(prefix).getOrDefault(0); +// BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); +// BigInteger remainingAmount = ProposalData.remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); +// Address contributorAddress = ProposalData.contributorAddress.at(prefix).get(); +// String flag = ProposalData.token.at(prefix).get(); + int installmentCount = (int) proposalData.get(consts.INSTALLMENT_COUNT); + BigInteger withdrawAmount = (BigInteger) proposalData.get(consts.WITHDRAW_AMOUNT); + BigInteger remainingAmount = (BigInteger) proposalData.get(consts.REMAINING_AMOUNT); + Address contributorAddress = (Address) proposalData.get(consts.CONTRIBUTOR_ADDRESS); + String flag = (String) proposalData.get(consts.TOKEN); try { if (installmentCount == 1) { @@ -343,15 +316,20 @@ public void send_installment_to_contributor(String _ipfs_key){ installmentAmount = remainingAmount.divide(BigInteger.valueOf(installmentCount)); } int newInstallmentCount = installmentCount - 1; - ProposalData.installmentCount.at(prefix).set(newInstallmentCount); - ProposalData.remainingAmount.at(prefix).set(remainingAmount.subtract(installmentAmount)); - ProposalData.withdrawAmount.at(prefix).set(withdrawAmount.add(installmentAmount)); +// ProposalData.installmentCount.at(prefix).set(newInstallmentCount); +// ProposalData.remainingAmount.at(prefix).set(remainingAmount.subtract(installmentAmount)); +// ProposalData.withdrawAmount.at(prefix).set(withdrawAmount.add(installmentAmount)); + + setInstallmentCount(prefix, newInstallmentCount); + setRemainingAmount(prefix, remainingAmount.subtract(installmentAmount)); + setWithdrawAmount(prefix, withdrawAmount.add(installmentAmount)); installmentFundRecord.at(contributorAddress.toString()).set(flag, installmentFundRecord.at(contributorAddress.toString()).get(flag).add(installmentAmount)); ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); if (newInstallmentCount == 0){ - ProposalData.status.at(prefix).set(COMPLETED); +// ProposalData.status.at(prefix).set(COMPLETED); + setStatus(prefix, COMPLETED); } } catch (Exception e){ @@ -361,17 +339,23 @@ public void send_installment_to_contributor(String _ipfs_key){ @External public void send_reward_to_sponsor(String _ipfs_key){ - _validate_cps_score(); + validateCpsScore(); - Context.require(_proposal_exists(_ipfs_key), TAG + ": Invalid IPFS Hash."); + Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); BigInteger installmentAmount = BigInteger.ZERO; - String prefix = proposal_prefix(_ipfs_key); - - int sponsorRewardCount = ProposalData.sponsorRewardCount.at(prefix).getOrDefault(0); - BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger sponsorRemainingAmount = ProposalData.sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); - Address sponsorAddress = ProposalData.sponsorAddress.at(prefix).get(); - String flag = ProposalData.token.at(prefix).get(); + String prefix = proposalPrefix(_ipfs_key); +// Map proposalData = getDataFromProposalDB(prefix); +// int sponsorRewardCount = ProposalData.sponsorRewardCount.at(prefix).getOrDefault(0); +// BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); +// BigInteger sponsorRemainingAmount = ProposalData.sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); +// Address sponsorAddress = ProposalData.sponsorAddress.at(prefix).get(); +// String flag = ProposalData.token.at(prefix).get(); + + int sponsorRewardCount = getSponsorRewardCount(prefix); + BigInteger sponsorWithdrawAmount = getSponsorWithdrawAmount(prefix); + BigInteger sponsorRemainingAmount = getSponsorRemainingAmount(prefix); + Address sponsorAddress = getSponsorAddress(prefix); + String flag = getToken(prefix); try { if (sponsorRewardCount == 1) { @@ -380,9 +364,13 @@ public void send_reward_to_sponsor(String _ipfs_key){ installmentAmount = sponsorRemainingAmount.divide(BigInteger.valueOf(sponsorRewardCount)); } int newSponsorRewardCount = sponsorRewardCount - 1; - ProposalData.sponsorRewardCount.at(prefix).set(newSponsorRewardCount); - ProposalData.sponsorWithdrawAmount.at(prefix).set(sponsorWithdrawAmount.add(installmentAmount)); - ProposalData.sponsorRemainingAmount.at(prefix).set(sponsorRemainingAmount.subtract(installmentAmount)); +// ProposalData.sponsorRewardCount.at(prefix).set(newSponsorRewardCount); +// ProposalData.sponsorWithdrawAmount.at(prefix).set(sponsorWithdrawAmount.add(installmentAmount)); +// ProposalData.sponsorRemainingAmount.at(prefix).set(sponsorRemainingAmount.subtract(installmentAmount)); + + setSponsorRewardCount(prefix, newSponsorRewardCount); + setSponsorWithdrawAmount(prefix, sponsorWithdrawAmount.add(installmentAmount)); + setSponsorRemainingAmount(prefix, sponsorRemainingAmount.subtract(installmentAmount)); installmentFundRecord.at(sponsorAddress.toString()).set(flag, installmentFundRecord.at(sponsorAddress.toString()).get(flag).add(installmentAmount)); ProposalFundSent(sponsorAddress, "New installment " + installmentAmount + " " + flag + " sent to sponsor address."); @@ -394,16 +382,23 @@ public void send_reward_to_sponsor(String _ipfs_key){ @External public void disqualify_project(String _ipfs_key){ - _validate_cps_score(); - Context.require(_proposal_exists(_ipfs_key), TAG + ": Project not found. Invalid IPFS hash."); - String prefix = proposal_prefix(_ipfs_key); - ProposalData.status.at(prefix).set(DISQUALIFIED); + validateCpsScore(); + Context.require(proposalExists(_ipfs_key), TAG + ": Project not found. Invalid IPFS hash."); + String prefix = proposalPrefix(_ipfs_key); + setStatus(prefix, DISQUALIFIED); + +// BigInteger totalBudget = ProposalData.totalBudget.at(prefix).getOrDefault(BigInteger.ZERO); +// BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); +// BigInteger sponsorReward = ProposalData.sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO); +// BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); +// String flag = ProposalData.token.at(prefix).get(); + + BigInteger totalBudget = getTotalBudget(prefix); + BigInteger withdrawAmount = getWithdrawAmount(prefix); + BigInteger sponsorReward = getSponsorReward(prefix); + BigInteger sponsorWithdrawAmount = getSponsorWithdrawAmount(prefix); + String flag = getToken(prefix); - BigInteger totalBudget = ProposalData.totalBudget.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger sponsorReward = ProposalData.sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO); - BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); - String flag = ProposalData.token.at(prefix).get(); BigInteger remainingBudget = totalBudget.subtract(withdrawAmount); BigInteger remainingReward = sponsorReward.subtract(sponsorWithdrawAmount); @@ -411,11 +406,11 @@ public void disqualify_project(String _ipfs_key){ try{ if (flag.equals(consts.ICX)){ - Context.call(totalReturnAmount, cpfTreasuryScore.get(), "disqualify_proposal_fund", _ipfs_key); + callScore(totalReturnAmount, cpfTreasuryScore.get(), "disqualify_proposal_fund", _ipfs_key); } else if(flag.equals(consts.bnUSD)){ String _data = "" + "{\"method\":\"disqualify_project\",\"params\":{\"ipfs_key\":" + "\"" + _ipfs_key + "\"" + "}}"; - Context.call(balancedDollar.get(), "transfer", cpfTreasuryScore.get(), totalReturnAmount, _data.getBytes()); + callScore(balancedDollar.get(), "transfer", cpfTreasuryScore.get(), totalReturnAmount, _data.getBytes()); } else{ Context.revert(TAG + ": Not supported token."); @@ -444,7 +439,7 @@ public void claim_reward(){ else if(availableAmountbnUSD.compareTo(BigInteger.ZERO) > 0){ try { installmentFundRecord.at(Context.getCaller().toString()).set(consts.bnUSD, BigInteger.ZERO); - Context.call(balancedDollar.get(), "transfer",Context.getCaller(), availableAmountbnUSD); + callScore(balancedDollar.get(), "transfer",Context.getCaller(), availableAmountbnUSD); } catch (Exception e){ Context.revert(TAG + ": Network problem while claiming reward."); @@ -478,7 +473,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data){ proposalAttributes.contributor_address = contributor_address; proposalAttributes.sponsor_address = sponsor_address; proposalAttributes.status = ACTIVE; - _deposit_proposal_fund(proposalAttributes, _value); + depositProposalFund(proposalAttributes, _value); } else if (jsonObject.get("method").asString().equals("budget_adjustment")){ String ipfs_key = params.get("_ipfs_key").asString(); @@ -494,6 +489,19 @@ else if (jsonObject.get("method").asString().equals("budget_adjustment")){ } + + public T callScore(Class t, Address address, String method, Object... params) { + return Context.call(t, address, method, params); + } + + public void callScore(Address address, String method, Object... params) { + Context.call(address, method, params); + } + + public void callScore(BigInteger amount, Address address, String method, Object... params) { + Context.call(amount, address, method, params); + } + @EventLog(indexed = 1) public void FundReturned(Address _sponsor_address, String note){} From c5e7dc88b64ff1cc1cc19ee7def8e747799ef9b4 Mon Sep 17 00:00:00 2001 From: swopnil Date: Mon, 25 Apr 2022 10:59:23 +0545 Subject: [PATCH 013/112] made all dbs private and added set and get methods --- .../score/CPSTreasury/db/ProposalData.java | 129 +++++++++++++++--- 1 file changed, 113 insertions(+), 16 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/db/ProposalData.java b/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/db/ProposalData.java index ee65f00c..17970b0d 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/db/ProposalData.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/db/ProposalData.java @@ -1,5 +1,6 @@ package community.icon.cps.score.CPSTreasury.db; +import jdk.jshell.Snippet; import score.*; import community.icon.cps.score.CPSTreasury.utils.consts; @@ -17,20 +18,20 @@ public static class ProposalAttributes{ public String sponsor_address; public String status; } - protected static final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); - protected static final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); - protected static final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSORS_REWARDS, BigInteger.class); - protected static final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); - protected static final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); - protected static final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); - protected static final BranchDB> token = Context.newBranchDB(consts.TOKEN, String.class); - protected static final BranchDB> withdrawAmount = Context.newBranchDB(consts.WITHDRAW_AMOUNT, BigInteger.class); - protected static final BranchDB> sponsorWithdrawAmount = Context.newBranchDB(consts.SPONSOR_WITHDRAW_AMOUNT, BigInteger.class); - protected static final BranchDB> remainingAmount = Context.newBranchDB(consts.REMAINING_AMOUNT, BigInteger.class); - protected static final BranchDB> sponsorRemainingAmount = Context.newBranchDB(consts.SPONSOR_REMAINING_AMOUNT, BigInteger.class); - protected static final BranchDB> installmentCount = Context.newBranchDB(consts.INSTALLMENT_COUNT, Integer.class); - protected static final BranchDB> sponsorRewardCount = Context.newBranchDB(consts.SPONSOR_REWARD_COUNT, Integer.class); - protected static final BranchDB> status = Context.newBranchDB(consts.STATUS, String.class); + private final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); + private final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); + private final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSORS_REWARDS, BigInteger.class); + private final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); + private final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); + private final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); + private final BranchDB> token = Context.newBranchDB(consts.TOKEN, String.class); + private final BranchDB> withdrawAmount = Context.newBranchDB(consts.WITHDRAW_AMOUNT, BigInteger.class); + private final BranchDB> sponsorWithdrawAmount = Context.newBranchDB(consts.SPONSOR_WITHDRAW_AMOUNT, BigInteger.class); + private final BranchDB> remainingAmount = Context.newBranchDB(consts.REMAINING_AMOUNT, BigInteger.class); + private final BranchDB> sponsorRemainingAmount = Context.newBranchDB(consts.SPONSOR_REMAINING_AMOUNT, BigInteger.class); + private final BranchDB> installmentCount = Context.newBranchDB(consts.INSTALLMENT_COUNT, Integer.class); + private final BranchDB> sponsorRewardCount = Context.newBranchDB(consts.SPONSOR_REWARD_COUNT, Integer.class); + private final BranchDB> status = Context.newBranchDB(consts.STATUS, String.class); @@ -58,8 +59,8 @@ public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ Map.entry(consts.TOTAL_BUDGET, totalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), Map.entry(consts.SPONSORS_REWARDS, sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO)), Map.entry(consts.PROJECT_DURATION, projectDuration.at(prefix).getOrDefault(0)), - Map.entry(consts.SPONSOR_ADDRESS, sponsorAddress.at(prefix).get().toString()), - Map.entry(consts.CONTRIBUTOR_ADDRESS, contributorAddress.at(prefix).get().toString()), + Map.entry(consts.SPONSOR_ADDRESS, sponsorAddress.at(prefix).get()), + Map.entry(consts.CONTRIBUTOR_ADDRESS, contributorAddress.at(prefix).get()), Map.entry(consts.WITHDRAW_AMOUNT, withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO)), Map.entry(consts.INSTALLMENT_COUNT, installmentCount.at(prefix).getOrDefault(0)), Map.entry(consts.SPONSOR_REWARD_COUNT, sponsorRewardCount.at(prefix).getOrDefault(0)), @@ -69,4 +70,100 @@ public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ Map.entry(consts.TOKEN, token.at(prefix).getOrDefault("")) ); } + + public String getIpfsHash(String prefix){ + return ipfsHash.at(prefix).get(); + } + + public Address getSponsorAddress(String prefix){ + return sponsorAddress.at(prefix).get(); + } + + public Address getContributorAddress(String prefix){ + return contributorAddress.at(prefix).get(); + } + + public void setTotalBudget(String prefix, BigInteger totalBudget){ + this.totalBudget.at(prefix).set(totalBudget); + } + + public BigInteger getTotalBudget(String prefix){ + return totalBudget.at(prefix).getOrDefault(BigInteger.ZERO); + } + + public void setSponsorReward(String prefix, BigInteger sponsorReward){ + this.sponsorReward.at(prefix).set(sponsorReward); + } + + public BigInteger getSponsorReward(String prefix){ + return sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO); + } + + public void setProjectDuration(String prefix, int projectDuration){ + this.projectDuration.at(prefix).set(projectDuration); + } + + public int getProjectDuration(String prefix){ + return projectDuration.at(prefix).getOrDefault(0); + } + + public void setWithdrawAmount(String prefix, BigInteger withdrawAmount){ + this.withdrawAmount.at(prefix).set(withdrawAmount); + } + + public BigInteger getWithdrawAmount(String prefix){ + return withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); + } + + public void setInstallmentCount(String prefix, int installmentCount){ + this.installmentCount.at(prefix).set(installmentCount); + } + + public int getInstallmentCount(String prefix){ + return installmentCount.at(prefix).getOrDefault(0); + } + + public void setSponsorRewardCount(String prefix, int sponsorRewardCount){ + this.sponsorRewardCount.at(prefix).set(sponsorRewardCount); + } + + public int getSponsorRewardCount(String prefix){ + return sponsorRewardCount.at(prefix).getOrDefault(0); + } + + public void setSponsorWithdrawAmount(String prefix, BigInteger sponsorWithdrawAmount){ + this.sponsorWithdrawAmount.at(prefix).set(sponsorWithdrawAmount); + } + + public BigInteger getSponsorWithdrawAmount(String prefix){ + return sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); + } + + public void setRemainingAmount(String prefix, BigInteger remainingAmount){ + this.remainingAmount.at(prefix).set(remainingAmount); + } + + public BigInteger getRemainingAmount(String prefix){ + return remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); + } + + public void setSponsorRemainingAmount(String prefix, BigInteger sponsorRemainingAmount){ + this.sponsorRemainingAmount.at(prefix).set(sponsorRemainingAmount); + } + + public BigInteger getSponsorRemainingAmount(String prefix){ + return sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); + } + + public void setStatus(String prefix, String status){ + this.status.at(prefix).set(status); + } + + public String getStatus(String prefix){ + return status.at(prefix).get(); + } + + public String getToken(String prefix){ + return token.at(prefix).get(); + } } From c836e3429293f3bc34bef7bd6a2e7381c2e28c06 Mon Sep 17 00:00:00 2001 From: swopnil Date: Mon, 25 Apr 2022 11:00:46 +0545 Subject: [PATCH 014/112] added CPS Treasury test --- .../score/CPSTreasury/CPSTreasuryTest.java | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/CPSTreasuryTest.java diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/CPSTreasuryTest.java new file mode 100644 index 00000000..1f36a1f8 --- /dev/null +++ b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/CPSTreasuryTest.java @@ -0,0 +1,160 @@ +package community.icon.cps.score.CPSTreasury; +import com.eclipsesource.json.JsonObject; +import com.iconloop.score.test.Account; +import com.iconloop.score.test.Score; +import com.iconloop.score.test.ServiceManager; +import com.iconloop.score.test.TestBase; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import org.mockito.Answers; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import score.Address; +import score.Context; +import score.DictDB; +import score.VarDB; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +public class CPSTreasuryTest extends TestBase{ + private static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); + private static final Address treasury_score = new Address(new byte[Address.LENGTH]); + private static final Address score_address = Address.fromString("cx0000000000000000000000000000000000000000"); + private static final Address sicxScore = Address.fromString("cx0000000000000000000000000000000000000001"); + private static final Address bnUSDScore = Address.fromString("cx0000000000000000000000000000000000000002"); + private static final Address dexScore = Address.fromString("cx0000000000000000000000000000000000000003"); + private static final Address cpsTreasuryScore = Address.fromString("cx0000000000000000000000000000000000000004"); + + private static final String name = "CPS_Treasury"; + public static final String TAG = "CPS_Treasury"; + CPSTreasury cpsTreasury; + private static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); + + + private static final ServiceManager sm = getServiceManager(); + private static final Account owner = sm.createAccount(); + private static final Account testing_account = sm.createAccount(); + private static final Account testing_account2 = sm.createAccount(); + + private Score tokenScore; + private final SecureRandom secureRandom = new SecureRandom(); + + DictDB proposalBudgets = Mockito.mock(DictDB.class); + VarDB swapState = Mockito.mock(VarDB.class); + VarDB swapCount = Mockito.mock(VarDB.class); + + CPSTreasury scoreSpy; + + @BeforeEach + public void setup() throws Exception { + tokenScore = sm.deploy(owner, CPSTreasury.class); + CPSTreasury instance = (CPSTreasury) tokenScore.getInstance(); + scoreSpy = spy(instance); + tokenScore.setInstance(scoreSpy); + } + + @Test + void name(){ + assertEquals(tokenScore.call("name"), name); + } + + + public void expectErrorMessage(Executable contractCall, String errorMessage) { + AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); + assertEquals(errorMessage, e.getMessage()); + } + + void fallbackExceptions(Account address) { + try { + sm.call(address, BigInteger.valueOf(1000).multiply(MULTIPLIER), tokenScore.getAddress(), "fallback"); + } catch (Exception e) { + throw e; + } + } + + @Test + void fallback(){ + Executable fallback = () -> fallbackExceptions(owner); + expectErrorMessage(fallback, "Reverted(0):" + " " + TAG + ": ICX can only be send by CPF Treasury Score"); + } + + @Test + void setCpsScore(){ + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + tokenScore.invoke(owner, "setCpsScore", score_address); + } + + @Test + void setCPFTreasuryScore(){ + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + tokenScore.invoke(owner, "setCpfTreasuryScore", score_address); + } + + @Test + void setBnUSDScore(){ + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + tokenScore.invoke(owner, "setBnUSDScore", score_address); + } + + void setCpsScoreExceptions(Boolean isAdmin, Address score_address){ + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + tokenScore.invoke(owner, "setCpsScore", score_address); + } + + void setCpfTreasuryScoreExceptions(Boolean isAdmin, Address score_address){ + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + tokenScore.invoke(owner, "setCpfTreasuryScore", score_address); + } + + void setBnUSDScoreExceptions(Boolean isAdmin, Address score_address){ + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + tokenScore.invoke(owner, "setBnUSDScore", score_address); + } + + @Test + void setCpsScoreNotAdmin() { + Executable setCpsScoreNotAdmin = () -> setCpsScoreExceptions(false, score_address); + expectErrorMessage(setCpsScoreNotAdmin, TAG + ": Only admins can call this method"); + } + + @Test + void setCpfTreasuryScoreNotAdmin() { + Executable setCpfTreasuryScoreNotAdmin = () -> setCpfTreasuryScoreExceptions(false, score_address); + expectErrorMessage(setCpfTreasuryScoreNotAdmin, TAG + ": Only admins can call this method"); + } + + @Test + void setBnUSDScoreNotAdmin() { + Executable setBnUSDScoreNotAdmin = () -> setBnUSDScoreExceptions(false, score_address); + expectErrorMessage(setBnUSDScoreNotAdmin, TAG + ": Only admins can call this method"); + } + + @Test + void setCPSScoreNotContract(){ + Executable setCpsScoreNotAdmin = () -> setCpsScoreExceptions(true, testing_account.getAddress()); + expectErrorMessage(setCpsScoreNotAdmin, TAG + "Target " + testing_account.getAddress() + " is not a score."); + } + + @Test + void setCPFTreasuryScoreNotContract(){ + Executable setCpfTreasuryScoreNotContract = () -> setCpfTreasuryScoreExceptions(true, testing_account.getAddress()); + expectErrorMessage(setCpfTreasuryScoreNotContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); + } + + @Test + void setBnUSDScoreNotContract(){ + Executable setBnUSDScoreContract = () -> setBnUSDScoreExceptions(true, testing_account.getAddress()); + expectErrorMessage(setBnUSDScoreContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); + } +} From c870e911f19ee767c7fbc66cf91e9471c0af2582 Mon Sep 17 00:00:00 2001 From: swopnil Date: Tue, 26 Apr 2022 11:08:23 +0545 Subject: [PATCH 015/112] changed the folder package name, deleted CPF Treasury files --- CPFTreasury/build.gradle | 57 -- .../cps/score/CPFTreasury/CPFTreasury.java | 568 ------------------ .../score/CPFTreasury/utils/ArrayDBUtils.java | 112 ---- .../score/CPFTreasury/utils/Eventlogs.java | 22 - .../score/CPFTreasury/CPFTTreasuryTest.java | 468 --------------- CPSTreasury/build.gradle | 7 +- .../icon/cps/score/CPSTreasury/test.java | 15 - .../cps/score/CPSTreasury/utils/Checks.java | 4 - .../CPSTreasury.java | 6 +- .../db/ProposalData.java | 5 +- .../utils/ArrayDBUtils.java | 2 +- .../cps/score/cpstreasury/utils/Checks.java | 4 + .../utils/Eventlogs.java | 2 +- .../utils/consts.java | 2 +- .../icon/cps/score/CPSTreasury/BasicTest.java | 73 --- .../icon/cps/score/CPSTreasury/DiceTest.java | 186 ------ .../cps/score/CPSTreasury/IRC2BasicTest.java | 90 --- .../score/CPSTreasury/IRC2BurnableTest.java | 92 --- .../cps/score/CPSTreasury/IRC2CappedTest.java | 124 ---- .../score/CPSTreasury/IRC2MintableTest.java | 133 ---- .../score/CPSTreasury/IRC2PausableTest.java | 125 ---- .../CPSTreasuryTest.java | 9 +- 22 files changed, 14 insertions(+), 2092 deletions(-) delete mode 100644 CPFTreasury/build.gradle delete mode 100644 CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/CPFTreasury.java delete mode 100644 CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/utils/ArrayDBUtils.java delete mode 100644 CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/utils/Eventlogs.java delete mode 100644 CPFTreasury/src/test/java/community/icon/cps/score/CPFTreasury/CPFTTreasuryTest.java delete mode 100644 CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/test.java delete mode 100644 CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/Checks.java rename CPSTreasury/src/main/java/community/icon/cps/score/{CPSTreasury => cpstreasury}/CPSTreasury.java (99%) rename CPSTreasury/src/main/java/community/icon/cps/score/{CPSTreasury => cpstreasury}/db/ProposalData.java (98%) rename CPSTreasury/src/main/java/community/icon/cps/score/{CPSTreasury => cpstreasury}/utils/ArrayDBUtils.java (98%) create mode 100644 CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/Checks.java rename CPSTreasury/src/main/java/community/icon/cps/score/{CPSTreasury => cpstreasury}/utils/Eventlogs.java (90%) rename CPSTreasury/src/main/java/community/icon/cps/score/{CPSTreasury => cpstreasury}/utils/consts.java (99%) delete mode 100644 CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/BasicTest.java delete mode 100644 CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/DiceTest.java delete mode 100644 CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2BasicTest.java delete mode 100644 CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2BurnableTest.java delete mode 100644 CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2CappedTest.java delete mode 100644 CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2MintableTest.java delete mode 100644 CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2PausableTest.java rename CPSTreasury/src/test/java/community/icon/cps/score/{CPSTreasury => cpstreasury}/CPSTreasuryTest.java (96%) diff --git a/CPFTreasury/build.gradle b/CPFTreasury/build.gradle deleted file mode 100644 index ec2db8cb..00000000 --- a/CPFTreasury/build.gradle +++ /dev/null @@ -1,57 +0,0 @@ -version = '0.9.1' - -dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.1' - implementation 'com.github.sink772:javaee-tokens:0.6.1' - implementation 'com.github.sink772:minimal-json:0.9.6' - - testImplementation 'foundation.icon:javaee-unittest:0.9.2' - implementation 'org.mockito:mockito-core:4.3.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation('org.mockito:mockito-inline:4.3.1') - implementation 'foundation.icon:javaee-scorex:0.5.2' - -} - -optimizedJar { - mainClassName = 'community.icon.cps.score.CPFTreasury.CPFTreasury' - from { - configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } - } -} - -deployJar { - endpoints { - lisbon { - uri = 'https://lisbon.net.solidwallet.io/api/v3' - nid = 0x2 - } - local { - uri = 'http://localhost:9082/api/v3' - nid = 0x3 - } - sejong { - uri = 'https://sejong.net.solidwallet.io/api/v3' - nid = 0x53 - - } - berlin { - uri = 'https://berlin.net.solidwallet.io/api/v3' - nid = 0x7 - to = 'cxe2488c05e6c61c36205b12dbd810690b79dd58e4' - } - } - keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' - password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' - parameters { - arg('amount', '0x30D40') -// arg('decimals', '0x12') -// arg('initialSupply', '0x3e8') -// arg('on_update_var','0x0') - } -} - -test { - useJUnitPlatform() -} diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/CPFTreasury.java b/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/CPFTreasury.java deleted file mode 100644 index 50338241..00000000 --- a/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/CPFTreasury.java +++ /dev/null @@ -1,568 +0,0 @@ -package community.icon.cps.score.CPFTreasury; - -import com.eclipsesource.json.Json; -import com.eclipsesource.json.JsonObject; -import community.icon.cps.score.CPFTreasury.utils.Eventlogs; -import score.*; -import score.annotation.External; -import score.annotation.Optional; -import score.annotation.Payable; -import scorex.util.ArrayList; - -import java.math.BigInteger; -import java.util.List; -import java.util.Map; - -public class CPFTreasury { - private static final BigInteger MULTIPLIER = BigInteger.valueOf(10 ^ 18); - private static final String TAG = "CPF_TREASURY"; - private static final String ICX = "ICX"; - private static final String bnUSD = "bnUSD"; - private static final String PROPOSAL_BUDGETS = "_proposals_budgets"; - private static final String PROPOSALS_KEYS = "_proposals_keys"; - private static final String CPS_TREASURY_SCORE = "_cps_treasury_score"; - private static final String CPS_SCORE = "_cps_score"; - private static final String TREASURY_FUND = "treasury_fund"; - private static final String TREASURY_FUND_BNUSD = "treasury_fund_bnusd"; - private static final String IPFS_HASH = "_ipfs_hash"; - private static final String TOTAL_BUDGET = "_budget_transfer"; - private static final String BALANCED_DOLLAR = "balanced_dollar"; - private static final String DEX_SCORE = "dex_score"; - private static final String SICX_SCORE = "sicx_score"; - private static final String STAKING_SCORE = "staking_score"; - private static final String ROUTER_SCORE = "router_score"; - private static final String SWAP_STATE = "swap_state"; - private static final String SWAP_COUNT = "swap_count"; - private static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000"); - private static final int sICXICXPoolID = 1; - private static final int sICXBNUSDPoolID = 2; - - - private static final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); - private static final DictDB proposalBudgets = Context.newDictDB(PROPOSAL_BUDGETS, BigInteger.class); - private static final VarDB treasuryFund = Context.newVarDB(TREASURY_FUND, BigInteger.class); - private static final VarDB treasuryFundBnUSd = Context.newVarDB(TREASURY_FUND_BNUSD, BigInteger.class); - - private static final VarDB
cpsTreasuryScore = Context.newVarDB(CPS_TREASURY_SCORE, Address.class); - private static final VarDB
cpsScore = Context.newVarDB(CPS_SCORE, Address.class); - private static final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); - private static final VarDB
dexScore = Context.newVarDB(DEX_SCORE, Address.class); - private static final VarDB
stakingScore = Context.newVarDB(STAKING_SCORE, Address.class); - private static final VarDB
sICXScore = Context.newVarDB(SICX_SCORE, Address.class); - private static final VarDB
routerScore = Context.newVarDB(ROUTER_SCORE, Address.class); - - private static final VarDB swapState = Context.newVarDB(SWAP_STATE, Integer.class); - private static final VarDB swapCount = Context.newVarDB(SWAP_COUNT, Integer.class); - - public CPFTreasury(int amount) { - treasuryFund.set(BigInteger.valueOf(amount).multiply(MULTIPLIER)); - } - - private boolean proposalExists(String _ipfs_key) { - return proposalBudgets.getOrDefault(_ipfs_key, null) != null; - } - - @External(readonly = true) - public String name() { - return TAG; - } - - private void validateAdmins() { - Context.require((Boolean) Context.call(cpsScore.get(), "is_admin", Context.getCaller()), - TAG + ": Only Admins can call this method"); - - } - - private void validateOwner() { - Context.require(Context.getCaller().equals(Context.getOwner()), - TAG + ": Only owner can call this method"); - } - - private void validateOwnerScore(Address _score) { - validateOwner(); - Context.require(_score.isContract(), TAG + ": Target " + _score + " is not a SCORE"); - } - - private void validateCpsScore(@Optional Address _from) { - if (_from == null) { - _from = Context.getCaller(); - } - Address _cpsScore = cpsScore.get(); - Context.require(_from.equals(_cpsScore), - TAG + ": Only " + _cpsScore + " SCORE can send fund using this method."); - } - - private void validateCpsTreasuryScore(@Optional Address _from) { - if (_from == null) { - _from = Context.getCaller(); - } - Address _cpsTreasuryScore = cpsTreasuryScore.get(); - Context.require(_from.equals(_cpsTreasuryScore), - TAG + ": Only " + _cpsTreasuryScore + " SCORE can send fund using this method."); - } - - /** - * Set the maximum Treasury fund. Default 1M in ICX - * - * @param _value: value in loop - */ - @External - public void setMaximumTreasuryFundIcx(BigInteger _value) { - validateAdmins(); - treasuryFund.set(_value); - } - - /** - * Set the maximum Treasury fund. Default 1M in bnUSD - * - * @param _value: value in loop - */ - @External - public void setMaximumTreasuryFundBnusd(BigInteger _value) { - validateAdmins(); - treasuryFundBnUSd.set(_value); - } - - - /** - * Sets the cps score address. Only owner can set the method - * - * @param _score: Score address of cps score - */ - @External - public void setCpsScore(Address _score) { - validateOwnerScore(_score); - cpsScore.set(_score); - } - - /** - * Returns the cps score address - * - * @return cps score address - */ - @External(readonly = true) - public Address getCpsScore() { - return cpsScore.get(); - } - - /** - * Sets the cps treasury score address. Only owner can set the method - * - * @param _score: Score address of cps treasury score - */ - @External - public void setCpsTreasuryScore(Address _score) { - validateOwnerScore(_score); - cpsTreasuryScore.set(_score); - } - - /** - * Returns the cps treasury score address - * - * @return cps treasury score address - */ - @External(readonly = true) - public Address getCpsTreasuryScore() { - return cpsTreasuryScore.get(); - } - - /** - * Sets the bnUSD score address. Only owner can set the method - * - * @param _score: Score address of bnUSD score - */ - @External - public void setBnUSDScore(Address _score) { - validateOwnerScore(_score); - balancedDollar.set(_score); - } - - /** - * Returns the bnUSD score address - * - * @return cps bnUSD address - */ - @External(readonly = true) - public Address getBnUSDScore() { - return balancedDollar.get(); - } - - /** - * Sets the sicx score address. Only owner can set the method - * - * @param _score: Score address of sicx score - */ - @External - public void setSicxScore(Address _score) { - validateOwnerScore(_score); - sICXScore.set(_score); - } - - /** - * Reruns the sicx score address - * - * @return sicx score address - */ - @External(readonly = true) - public Address getSicxScore() { - return sICXScore.get(); - } - - /** - * Sets the dex score address. Only owner can set the method - * - * @param _score: Score address of dex score - */ - @External - public void setDexScore(Address _score) { - validateOwnerScore(_score); - dexScore.set(_score); - } - - /** - * Returns the dex score address - * - * @return dex score address - */ - @External(readonly = true) - public Address getDexScore() { - return dexScore.get(); - } - - /** - * Sets the router score address. Only owner can set the method - * - * @param _score: Score address of router score - */ - @External - public void setRouterScore(Address _score) { - validateOwnerScore(_score); - routerScore.set(_score); - } - - /** - * Returns the router score address - * - * @return router score address - */ - @External(readonly = true) - public Address getRouterScore() { - return routerScore.get(); - } - - /** - * Burns ICX method - * - * @param amount: amount to burn in loop - */ - private void _burn(BigInteger amount) { - Context.call(amount, SYSTEM_ADDRESS, "burn"); - } - - /** - * @return - */ - @External(readonly = true) - public Map get_total_funds() { - return Map.of(ICX, Context.getBalance(Context.getAddress()), - bnUSD, getTotalFundBNUSD()); - } - - private BigInteger getTotalFundBNUSD() { - return (BigInteger) Context.call(balancedDollar.get(), "balanceOf", Context.getAddress()); - } - - @External(readonly = true) - public Map get_remaining_swap_amount() { - BigInteger maxCap = treasuryFundBnUSd.get(); - return Map.of("maxCap", maxCap, - "remainingToSwap", maxCap.subtract(getTotalFundBNUSD())); - } - - @External - @Payable - public void return_fund_amount(Address _address, @Optional Address _from, @Optional String _flag, @Optional BigInteger _value) { - if (_from == null) { - _from = Context.getCaller(); - } - if (_flag == null) { - _flag = ICX; - } - if (_value == null) { - _value = BigInteger.ZERO; - } - validateCpsScore(_from); - burnExtraFund(); - if (_flag.equals(ICX)) { - _value = Context.getValue(); - } - Eventlogs.FundReturned(_address, "Sponsor Bond amount " + _value + " " + _flag + " Returned to CPF Treasury."); - } - - @External - public void transfer_proposal_fund_to_cps_treasury(String _ipfs_key, int _total_installment_count, - Address _sponsor_address, Address _contributor_address, - String token_flag, BigInteger _total_budget) { - validateCpsScore(null); - Context.require(!proposalExists(_ipfs_key), TAG + ": Project already exists. Invalid IPFS Hash"); - Context.require(token_flag.equals(bnUSD), TAG + ": " + token_flag + " is not supported. Only " + bnUSD + " token available."); - BigInteger _sponsor_reward = _total_budget.multiply(BigInteger.TWO).divide(BigInteger.valueOf(100)); - BigInteger total_transfer = _total_budget.add(_sponsor_reward); - - BigInteger balanceOf = (BigInteger) Context.call(balancedDollar.get(), "balanceOf", Context.getAddress()); - Context.require(balanceOf.compareTo(total_transfer) > 0, TAG + ": Not enough fund " + balanceOf + " token available"); - proposalsKeys.add(_ipfs_key); - proposalBudgets.set(_ipfs_key, total_transfer); - JsonObject jsonObject = new JsonObject(); - jsonObject.add("method", "deposit_proposal_fund"); - JsonObject params = new JsonObject(); - params.add("ipfs_hash", _ipfs_key); - params.add("project_duration", String.valueOf(_total_installment_count)); - params.add("sponsor_address", _sponsor_address.toString()); - params.add("contributor_address", _contributor_address.toString()); - params.add("totalBudget", _total_budget.toString()); - params.add("sponsor_reward", _sponsor_reward.toString()); - params.add("token", token_flag); - jsonObject.add("params", params); - String jsonString = String.valueOf(jsonObject); - - Context.call(balancedDollar.get(), "transfer", cpsTreasuryScore.get(), total_transfer, jsonString.getBytes()); - Eventlogs.ProposalFundTransferred(_ipfs_key, "Successfully transferred " + total_transfer + " " + token_flag + " to CPS Treasury " + cpsTreasuryScore.get()); - } - - @External - public void update_proposal_fund(String _ipfs_key, String _flag, @Optional BigInteger _added_budget, @Optional BigInteger _total_installment_count) { - validateCpsScore(null); - Context.require(proposalExists(_ipfs_key), TAG + ": IPFS hash does not exist."); - Context.require(_flag.equals(bnUSD), TAG + ": Unsupported token. " + _flag); - - if (_added_budget == null) { - _added_budget = BigInteger.ZERO; - } - - if (_total_installment_count == null) { - _total_installment_count = BigInteger.ZERO; - } - - BigInteger sponsorReward = _added_budget.multiply(BigInteger.TWO).divide(BigInteger.valueOf(100)); - BigInteger totalTransfer = _added_budget.add(sponsorReward); - - BigInteger proposalBudget = proposalBudgets.getOrDefault(_ipfs_key, BigInteger.ZERO); - proposalBudgets.set(_ipfs_key, proposalBudget.add(totalTransfer)); - BigInteger bnUSDFund = get_total_funds().get(bnUSD); - Context.require(bnUSDFund.compareTo(totalTransfer) >= 0, TAG + ": Not enough " + totalTransfer + " BNUSD on treasury"); - JsonObject jsonObject = new JsonObject(); - jsonObject.add("method", "budget_adjustment"); - JsonObject params = new JsonObject(); - params.add("_ipfs_key", _ipfs_key); - params.add("_added_budget", _added_budget.toString()); - params.add("_added_sponsor_reward", sponsorReward.toString()); - params.add("_added_installment_count", _total_installment_count.toString()); - jsonObject.add("params", params); - String jsonString = String.valueOf(jsonObject); - - Context.call(balancedDollar.get(), "transfer", cpsTreasuryScore.get(), totalTransfer, jsonString.getBytes()); - Eventlogs.ProposalFundTransferred(_ipfs_key, "Successfully transferred " + totalTransfer + " " + bnUSD + " to CPS Treasury"); - } - - @External - @Payable - public void disqualify_proposal_fund(String _ipfs_key, @Optional BigInteger _value, @Optional String _flag, - @Optional Address _from) { - if (_value == null) { - _value = BigInteger.ZERO; - } - if (_flag == null) { - _flag = ICX; - } - - validateCpsTreasuryScore(_from); - Context.require(proposalExists(_ipfs_key), TAG + ": IPFS key does not exist."); - Context.require(_flag.equals(bnUSD), TAG + ": Not supported token." + _flag); - - BigInteger _budget = proposalBudgets.get(_ipfs_key); - proposalBudgets.set(_ipfs_key, _budget.subtract(_value)); - - burnExtraFund(); - Eventlogs.ProposalDisqualified(_ipfs_key, "Proposal disqualified. " + _value + " " + _flag + " is returned back to Treasury."); - } - - @External - @Payable - public void add_fund() { - burnExtraFund(); - Eventlogs.FundReceived(Context.getCaller(), "Treasury fund " + Context.getValue() + " " + ICX + " received."); - } - - private void burnExtraFund() { - Map amounts = get_total_funds(); - BigInteger icxAmount = amounts.get(ICX); - BigInteger bnUSDAmount = amounts.get(bnUSD); - BigInteger extraAmountIcx = icxAmount.subtract(treasuryFund.get()); - BigInteger extraAmountBnUSD = bnUSDAmount.subtract(treasuryFundBnUSd.get()); - - if (extraAmountIcx.compareTo(BigInteger.ZERO) > 0) { - _burn(extraAmountIcx); - } - - if (extraAmountBnUSD.compareTo(BigInteger.ZERO) > 0) { - _swapTokens(balancedDollar.get(), sICXScore.get(), extraAmountBnUSD); - } - } - - private void _swapTokens(Address _from, Address _to, BigInteger _amount) { - JsonObject jsonObject = new JsonObject(); - jsonObject.add("method", "_swap"); - JsonObject params = new JsonObject(); - params.add("toToken", _to.toString()); - jsonObject.add("params", params); - String jsonString = String.valueOf(jsonObject); - Context.call(_from, "transfer", dexScore.get(), _amount, jsonString.getBytes()); - } - - @External - public void swap_icx_bnusd(BigInteger _amount) { - Address[] path = new Address[]{sICXScore.get(), balancedDollar.get()}; - Context.call(_amount, routerScore.get(), "route", (Object[]) path); - } - - @External - public void swap_tokens(int _count) { - validateCpsScore(null); - BigInteger sicxICXPrice = (BigInteger) Context.call(dexScore.get(), "getPrice", sICXICXPoolID); - BigInteger sicxBnusdPrice = (BigInteger) Context.call(dexScore.get(), "getPrice", sICXBNUSDPoolID); - BigInteger icxbnUSDPrice = sicxBnusdPrice.multiply(MULTIPLIER).divide(sicxICXPrice); - BigInteger bnUSDRemainingToSwap = get_remaining_swap_amount().get("remainingToSwap"); - if (bnUSDRemainingToSwap.compareTo(BigInteger.TEN.multiply(MULTIPLIER)) < 0 || _count == 0) { - swapState.set(1); - swapCount.set(0); - } - int swap_state = swapState.getOrDefault(0); - if (swap_state == 0) { - int swap_count = swapCount.getOrDefault(0); - int count = _count - swap_count; - if (count == 0) { - swapState.set(1); - swapCount.set(0); - } else { - BigInteger remainingICXToSwap = bnUSDRemainingToSwap.multiply(MULTIPLIER).divide(icxbnUSDPrice.multiply(BigInteger.valueOf(count))); - BigInteger icxBalance = Context.getBalance(Context.getAddress()); - if (remainingICXToSwap.compareTo(icxBalance) > 0) { - remainingICXToSwap = icxBalance; - } - - if (remainingICXToSwap.compareTo(BigInteger.valueOf(5).multiply(MULTIPLIER)) > 0) { - swap_icx_bnusd(remainingICXToSwap); - } - } - } - } - - @External(readonly = true) - public Map get_swap_state_status() { - return Map.of("state", swapState.get(), "count", swapCount.get()); - } - - @External - public void reset_swap_state() { - Address cps_score_address = cpsScore.get(); - Address caller = Context.getCaller(); - - boolean checkCaller = caller.equals(cps_score_address) || (Boolean) Context.call(cps_score_address, "is_admin", caller); - Context.require(checkCaller, TAG + ": Only admin can call this method."); - swapState.set(0); - swapCount.set(0); - } - - @External(readonly = true) - public List> get_proposal_details(int _start_index, int _end_index) { - List> proposalsList = new ArrayList<>(); - if ((_end_index - _start_index) > 50) { - Context.revert("Page Length cannot be greater than 50"); - } - int count = proposalsKeys.size(); - - if (_start_index < 0 || _start_index > count) { - _start_index = 0; - } - - if (_end_index > count) { - _end_index = count; - - } - - for (int i = _start_index; i < _end_index; i++) { - Map proposalDetails = Map.of(TOTAL_BUDGET, proposalBudgets.getOrDefault(proposalsKeys.get(i), BigInteger.ZERO).toString(), - IPFS_HASH, proposalsKeys.get(i)); - proposalsList.add(proposalDetails); - } - proposalsList.add(Map.of("count", String.valueOf(count))); - return proposalsList; - } - - @External - public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { - String unpacked_data = new String(_data); - Address bnUSDScore = balancedDollar.get(); - Address sICX = sICXScore.get(); - - Address caller = Context.getCaller(); - Context.require(caller.equals(bnUSDScore) || caller.equals(sICX), TAG + " Only " + bnUSDScore + " and " + sICX + " can send tokens to CPF Treasury."); - if (caller.equals(sICX)) { - if (_from.equals(dexScore.get())) { - JsonObject jsonObject = new JsonObject(); - jsonObject.add("method", "_swap_icx"); - String jsonString = String.valueOf(jsonObject); - Context.call(dexScore.get(), "transfer", _value, jsonString.getBytes()); - } - } else { - JsonObject json = Json.parse(unpacked_data).asObject(); - if (_from.equals(cpsScore.get())) { - if (json.get("method").asString().equals("return_fund_amount")) { - Address _sponsor_address = Address.fromString(json.get("params").asObject().get("sponsor_address").asString()); - return_fund_amount(_sponsor_address, _from, bnUSD, _value); - } else if (json.get("method").asString().equals("burn_amount")) { - _swapTokens(caller, sICX, _value); - } else { - Context.revert(TAG + " Not supported method " + json.get("method")); - } - } else if (_from.equals(cpsTreasuryScore.get())) { - if (json.get("method").asString().equals("disqualify_project")) { - String ipfs_key = json.get("params").asObject().get("ipfs_key").asString(); - disqualify_proposal_fund(ipfs_key, _value, bnUSD, _from); - } else { - Context.revert(TAG + " Not supported method " + json.get("method")); - } - } else if (_from.equals(dexScore.get()) || _from.equals(routerScore.get())) { - burnExtraFund(); - } - } - } - - @Payable - public void fallback() { - if (Context.getCaller().equals(routerScore.get())) { - _burn(Context.getValue()); - } else { - add_fund(); - } - } - - @External(readonly = true) - public List getProposalKeys() { - List ipfsHash = new ArrayList<>(); - for (int i = 0; i < proposalsKeys.size(); i++) { - ipfsHash.add(proposalsKeys.get(i)); - } - return ipfsHash; - } - - @External(readonly = true) - public BigInteger getProposalBudgets(String ipfsHash) { - return treasuryFundBnUSd.get(); - } - - @External - public void setProposalKeysAndBudgets() { - } -} diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/utils/ArrayDBUtils.java b/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/utils/ArrayDBUtils.java deleted file mode 100644 index d35a2e1c..00000000 --- a/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/utils/ArrayDBUtils.java +++ /dev/null @@ -1,112 +0,0 @@ -package community.icon.cps.score.CPFTreasury.utils; - -import score.Address; -import score.ArrayDB; -import score.Context; - -import java.util.ArrayList; -import java.util.List; - -public final class ArrayDBUtils { - - ArrayDBUtils() {} - - @SuppressWarnings("unchecked") - public static List removeElement(List list, E element){ - E[] array = (E[])list.toArray(); - - boolean found = false; - for(int i = 0; i < array.length; i++) { - if(array[i].equals(element)) { - int numMoved = array.length - i - 1; - System.arraycopy(array, i+1, array, i, numMoved); - found = true; - break; - } - } - if(!found) { - return list; - } - - array[array.length-1] = null; - - Object[] result = new Object[array.length-1]; - - System.arraycopy(array, 0, result, 0, result.length); - - return List.of((E[])result); - } - - @SuppressWarnings("unchecked") - public static List removeElementIndex(List list, int index){ - E[] array = (E[])list.toArray(); - - if(index >= list.size()) { - return list; - } - - int numMoved = array.length - index - 1; - System.arraycopy(array, index+1, array, index, numMoved); - - array[array.length-1] = null; - - Object[] result = new Object[array.length-1]; - - System.arraycopy(array, 0, result, 0, result.length); - - return List.of((E[])result); - } - - public static void removeElementIndexFromArrayDB(ArrayDB arrayDB, int index){ - List username_list = new ArrayList<>(); - if (index > arrayDB.size()-1){ - Context.revert("ArrayDB out of index"); - } - if (index == arrayDB.size() - 1) - for(int j = index + 1; j > arrayDB.size() - 1; j++){ - username_list.add(arrayDB.get(j)); - } - arrayDB.removeLast(); - - for (int i = 0; i > username_list.size() - 1; i++){ - arrayDB.add(username_list.get(i)); - } - } - - public static boolean remove_array_item_address(ArrayDB
array_db, Object target){ - int size = array_db.size(); - Address _out = array_db.get(size - 1); - if (_out.equals(target)){ - array_db.pop(); - return true; - } - for (int i = 0; i < size - 1; i++){ - if (array_db.get(i).equals(target)){ - array_db.set(i, _out); - array_db.pop(); - return true; - } - } - return false; - } - - public static boolean remove_array_item_string(ArrayDB array_db, Object target){ - int size = array_db.size(); - String _out = array_db.get(size - 1); - if (_out.equals(target)){ - array_db.pop(); - return true; - } - for (int i = 0; i < size - 1; i++){ - if (array_db.get(i).equals(target)){ - array_db.set(i, _out); - array_db.pop(); - return true; - } - } - return false; - } - -} - - diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/utils/Eventlogs.java b/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/utils/Eventlogs.java deleted file mode 100644 index a5b11871..00000000 --- a/CPFTreasury/src/main/java/community/icon/cps/score/CPFTreasury/utils/Eventlogs.java +++ /dev/null @@ -1,22 +0,0 @@ -package community.icon.cps.score.CPFTreasury.utils; -import score.Address; -import score.annotation.EventLog; - - -public class Eventlogs { - @EventLog(indexed = 1) - public static void FundReturned(Address _sponsor_address, String note) { - } - - @EventLog(indexed = 1) - public static void ProposalFundTransferred(String _ipfs_key, String note) { - } - - @EventLog(indexed = 1) - public static void ProposalDisqualified(String _ipfs_key, String note) { - } - - @EventLog(indexed = 1) - public static void FundReceived(Address _sponsor_address, String note) { - } -} diff --git a/CPFTreasury/src/test/java/community/icon/cps/score/CPFTreasury/CPFTTreasuryTest.java b/CPFTreasury/src/test/java/community/icon/cps/score/CPFTreasury/CPFTTreasuryTest.java deleted file mode 100644 index 3e73f1f8..00000000 --- a/CPFTreasury/src/test/java/community/icon/cps/score/CPFTreasury/CPFTTreasuryTest.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright 2020 ICONLOOP Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package community.icon.cps.score.CPFTreasury; - -import com.iconloop.score.test.Account; -import com.iconloop.score.test.Score; -import com.iconloop.score.test.ServiceManager; -import com.iconloop.score.test.TestBase; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import score.Address; -import org.junit.jupiter.api.function.Executable; - -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.List; -import java.util.Map; - -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import score.Context; -import score.DictDB; -import score.VarDB; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; - -public class CPFTTreasuryTest extends TestBase { - private static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); - private static final Address treasury_score = new Address(new byte[Address.LENGTH]); - private static final Address score_address = Address.fromString("cx0000000000000000000000000000000000000000"); - private static final String name = "CPF_TREASURY"; - private static final String symbol = "CPF_TREASURY"; - public static final String TAG = "CPF_TREASURY"; - CPFTreasury cpfTreasury; - private static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); - - - private static final ServiceManager sm = getServiceManager(); - private static final Account owner = sm.createAccount(); - private static final Account testing_account = sm.createAccount(); - private static final Account testing_account2 = sm.createAccount(); - - private Score tokenScore; - private final SecureRandom secureRandom = new SecureRandom(); - - DictDB proposalBudgets = Mockito.mock(DictDB.class); - VarDB swapState = Mockito.mock(VarDB.class); - VarDB swapCount = Mockito.mock(VarDB.class); - - @BeforeEach - public void setup() throws Exception { - tokenScore = sm.deploy(owner, CPFTreasury.class, 1000); - } - - @Test - void name() { - assertEquals(name, tokenScore.call("name")); - } - - - public void setMaximumTreasuryFundICXExceptions(Account address) { - try { - tokenScore.invoke(address, "setMaximumTreasuryFundBnusd", BigInteger.valueOf(100)); - } catch (Exception e) { - throw e; - } - } - - public void setMaximumTreasuryFundBNUSDExceptions(Account address) { - try { - tokenScore.invoke(address, "set_maximum_treasury_fund_bnusd", BigInteger.valueOf(100 * 10 ^ 18)); - } catch (Exception e) { - throw e; - } - } - - @Test - void setCPSScore() { - tokenScore.invoke(owner, "setCpsScore", score_address); - assertEquals(score_address, tokenScore.call("getCpsScore")); - } - - @Test - void setCPSTreasuryScore() { - tokenScore.invoke(owner, "setCpsTreasuryScore", score_address); - assertEquals(score_address, tokenScore.call("getCpsTreasuryScore")); - } - - @Test - void setBMUSDScore() { - tokenScore.invoke(owner, "setBnUSDScore", score_address); - assertEquals(score_address, tokenScore.call("getBnUSDScore")); - } - - @Test - void setSICXScore() { - tokenScore.invoke(owner, "setSicxScore", score_address); - assertEquals(score_address, tokenScore.call("getSicxScore")); - } - - @Test - void setDEXScore() { - tokenScore.invoke(owner, "setDexScore", score_address); - assertEquals(score_address, tokenScore.call("getDexScore")); - } - - @Test - void setRouterScore() { - tokenScore.invoke(owner, "setRouterScore", score_address); - assertEquals(score_address, tokenScore.call("getRouterScore")); - } - - void setCPSScoreExceptions(Account address, Address _score) { - try { - tokenScore.invoke(address, "setCpsScore", _score); - } catch (Exception e) { - throw e; - } - } - - void setCPSTreasuryScoreExceptions(Account address, Address _score) { - try { - tokenScore.invoke(address, "setCpsTreasuryScore", _score); - } catch (Exception e) { - throw e; - } - } - - void setBNUSDScoreExceptions(Account address, Address _score) { - try { - tokenScore.invoke(address, "setBnUSDScore", _score); - } catch (Exception e) { - throw e; - } - } - - void setSICXScoreExceptions(Account address, Address _score) { - try { - tokenScore.invoke(address, "setSicxScore", _score); - } catch (Exception e) { - throw e; - } - } - - void setDEXScoreExceptions(Account address, Address _score) { - try { - tokenScore.invoke(address, "setDexScore", _score); - } catch (Exception e) { - throw e; - } - } - - void setRouterScoreExceptions(Account address, Address _score) { - try { - tokenScore.invoke(address, "setRouterScore", _score); - } catch (Exception e) { - throw e; - } - } - - @Test - void setCPSScoreNotOwner() { - Executable setCPSScoreNotOwner = () -> setCPSScoreExceptions(testing_account, score_address); - expectErrorMessage(setCPSScoreNotOwner, TAG + ": Only owner can call this method"); - } - - @Test - void setCPSTreasuryScoreNotOwner() { - Executable setCPSTreasuryScoreNotOwner = () -> setCPSTreasuryScoreExceptions(testing_account, score_address); - expectErrorMessage(setCPSTreasuryScoreNotOwner, TAG + ": Only owner can call this method"); - } - - @Test - void setBNUSDScoreNotOwner() { - Executable setbnUSDScoreNotOwner = () -> setBNUSDScoreExceptions(testing_account, score_address); - expectErrorMessage(setbnUSDScoreNotOwner, TAG + ": Only owner can call this method"); - } - - @Test - void setSICXScoreNotOwner() { - Executable setSICXScoreNotOwner = () -> setSICXScoreExceptions(testing_account, score_address); - expectErrorMessage(setSICXScoreNotOwner, TAG + ": Only owner can call this method"); - } - - @Test - void setDEXScoreNotOwner() { - Executable setDEXScoreNotOwner = () -> setDEXScoreExceptions(testing_account, score_address); - expectErrorMessage(setDEXScoreNotOwner, TAG + ": Only owner can call this method"); - } - - @Test - void setRouterScoreNotOwner() { - Executable setRouterScoreNotOwner = () -> setRouterScoreExceptions(testing_account, score_address); - expectErrorMessage(setRouterScoreNotOwner, TAG + ": Only owner can call this method"); - } - - @Test - void transferProposalFundToCPSTreasury() { - tokenScore.invoke(owner, "setCpsScore", score_address); - VarDB
balancedDollar = Mockito.mock(VarDB.class); - - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock. - when(() -> Context.getCaller()). - thenReturn(score_address); - Mockito.when(proposalBudgets.getOrDefault("Proposal 1", null)).thenReturn(BigInteger.valueOf(10)); - theMock.when(() -> Context.getAddress()).thenReturn(tokenScore.getAddress()); - theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", tokenScore.getAddress())).thenReturn(BigInteger.valueOf(1000 * 10 ^ 18)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 1", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(10)); - System.out.println(tokenScore.call("getProposalKeys")); - System.out.println(tokenScore.call("getProposalBudgets", "Proposal 1")); - } catch (Exception e) { - throw e; - } - } - - @Test - void updateProposalFund() { - VarDB
balancedDollar = mock(VarDB.class); - transferProposalFundMethod(); - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(score_address); - theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "update_proposal_fund", "Proposal 1", "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER), BigInteger.valueOf(1)); - List> details = (List>) tokenScore.call("get_proposal_details", 0, 5); - Map expected = Map.of("_budget_transfer", BigInteger.valueOf(204).multiply(MULTIPLIER).divide(BigInteger.ONE), "_ipfs_hash", "Proposal 1"); - assertEquals(details.get(0).get("_budget_transfer"), expected.get("_budget_transfer").toString()); - - } - } - - void setMaxCapIcxAndBnusd(){ - VarDB
cpsScore = mock(VarDB.class); - try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); - tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "setMaximumTreasuryFundBnusd", BigInteger.valueOf(2000).multiply(MULTIPLIER)); - - } - } - - @Test - void setMaxCapIcxAndBnusdTest(){ - VarDB
cpsScore = mock(VarDB.class); - try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); - tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "setMaximumTreasuryFundBnusd", BigInteger.valueOf(2000).multiply(MULTIPLIER)); - - } - } - - @Test - void disqualifyProposalFund() { - setMaxCapIcxAndBnusd(); - - transferProposalFundMethod(); - VarDB
balancedDollar = mock(VarDB.class); - - tokenScore.invoke(owner, "setCpsTreasuryScore", score_address); - try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "disqualify_proposal_fund", "Proposal 1", BigInteger.valueOf(80).multiply(MULTIPLIER), "bnUSD", score_address); - } - System.out.println(tokenScore.call("get_proposal_details", 0,5)); - - } - - @Test - void swapTokens() { - VarDB
balancedDollar = mock(VarDB.class); - VarDB
dexScore = mock(VarDB.class); - VarDB
cpsScore = mock(VarDB.class); - - tokenScore.invoke(owner, "setCpsTreasuryScore", score_address); - tokenScore.invoke(owner, "setProposalKeysAndBudgets"); - - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); - tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "setMaximumTreasuryFundBnusd", BigInteger.valueOf(2000).multiply(MULTIPLIER)); - System.out.println("balue" + BigInteger.valueOf(2000).multiply(MULTIPLIER)); - System.out.println(tokenScore.call("getProposalBudgets", "Proposal 1")); - theMock.when(() -> Context.getCaller()).thenReturn(score_address); - theMock.when(() -> Context.call(dexScore.get(), "getPrice", 1)).thenReturn(BigInteger.valueOf(12).multiply(MULTIPLIER).divide(BigInteger.TEN)); - theMock.when(() -> Context.call(dexScore.get(), "getPrice", 2)).thenReturn(BigInteger.valueOf(8).multiply(MULTIPLIER).divide(BigInteger.TEN)); - theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - Mockito.when(swapState.getOrDefault(0)).thenReturn(10); - - Mockito.when(swapCount.getOrDefault(0)).thenReturn(0); - theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(10000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "swap_tokens", 10); - } - } - - @Test - void resetSwapState() { - setMaxCapIcxAndBnusd(); - VarDB
cpsScore = mock(VarDB.class); - VarDB swapState = mock(VarDB.class); - swapState.set(10); - tokenScore.invoke(owner, "setCpsScore", score_address); - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(testing_account.getAddress()); - theMock.when(() -> Context.call(score_address, "is_admin", Context.getCaller())).thenReturn(true); - tokenScore.invoke(owner, "reset_swap_state"); - assertEquals(tokenScore.call("get_swap_state_status"), Map.of("state", 0, "count", 0)); - } - } - - private void transferProposalFundMethod() { - VarDB
balancedDollar = mock(VarDB.class); - - tokenScore.invoke(owner, "setCpsScore", score_address); - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(score_address); - theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 1", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 2", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(110).multiply(MULTIPLIER)); - - - } - System.out.println(tokenScore.call("get_proposal_details", 0, 5)); - } - - @Test - void returnFundAmountExtraBnUSD(){ - setMaxCapIcxAndBnusd(); - VarDB
balancedDollar = mock(VarDB.class); - tokenScore.invoke(owner, "setCpsScore", score_address); - tokenScore.invoke(owner, "setBnUSDScore", score_address); - tokenScore.invoke(owner, "setDexScore", score_address); - tokenScore.invoke(owner, "setSicxScore", score_address); - - try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); - theMock.when(() -> Context.call(score_address, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "return_fund_amount", owner.getAddress(), score_address, "bnUSD", BigInteger.valueOf(2001).multiply(MULTIPLIER)); - - } - } - - @Test - void returnFundAmountExtraICX(){ - setMaxCapIcxAndBnusd(); - VarDB
balancedDollar = mock(VarDB.class); - tokenScore.invoke(owner, "setCpsScore", score_address); - tokenScore.invoke(owner, "setBnUSDScore", score_address); - tokenScore.invoke(owner, "setDexScore", score_address); - tokenScore.invoke(owner, "setSicxScore", score_address); - - try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); - theMock.when(() -> Context.call(score_address, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "return_fund_amount", owner.getAddress(), score_address, "bnUSD", BigInteger.valueOf(2001).multiply(MULTIPLIER)); - - } - } - - @Test - void addFundExtraICX(){ - setMaxCapIcxAndBnusd(); - VarDB
balancedDollar = mock(VarDB.class); - tokenScore.invoke(owner, "setCpsScore", score_address); - tokenScore.invoke(owner, "setBnUSDScore", score_address); - tokenScore.invoke(owner, "setDexScore", score_address); - tokenScore.invoke(owner, "setSicxScore", score_address); - - try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); - theMock.when(() -> Context.call(score_address, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "add_fund"); - - } - } - - @Test - void addFundExtraBnUSD(){ - setMaxCapIcxAndBnusd(); - VarDB
balancedDollar = mock(VarDB.class); - tokenScore.invoke(owner, "setCpsScore", score_address); - tokenScore.invoke(owner, "setBnUSDScore", score_address); - tokenScore.invoke(owner, "setDexScore", score_address); - tokenScore.invoke(owner, "setSicxScore", score_address); - - try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); - theMock.when(() -> Context.call(score_address, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "add_fund"); - - } - } - - public void expectErrorMessage(Executable contractCall, String errorMessage) { - AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); - assertEquals(errorMessage, e.getMessage()); - } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index 43b2975a..3be37cef 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -15,7 +15,7 @@ dependencies { } optimizedJar { - mainClassName = 'community.icon.cps.score.CPSTreasury.CPSTreasury' + mainClassName = 'community.icon.cps.score.cpstreasury.CPSTreasury' from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } @@ -40,11 +40,6 @@ deployJar { keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' parameters { - arg('name', 'CPSTreasury') - arg('symbol', 'CPSTreasury') -// arg('decimals', '0x12') -// arg('initialSupply', '0x3e8') -// arg('on_update_var','0x0') } } diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/test.java b/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/test.java deleted file mode 100644 index 914d5cee..00000000 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/test.java +++ /dev/null @@ -1,15 +0,0 @@ -package community.icon.cps.score.CPSTreasury; - -import java.nio.charset.StandardCharsets; -import java.util.Map; -import com.eclipsesource.json.Json; -import com.eclipsesource.json.JsonObject; - -public class test { - public static void main(String[] args) throws Exception { - // Create raw data. - String prefix = "proposal" + "|" + "10" + "|" + "proposal_key"; - byte[] prefix_byte = prefix.getBytes(); - System.out.println(prefix_byte); - } -} \ No newline at end of file diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/Checks.java b/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/Checks.java deleted file mode 100644 index 352c547b..00000000 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/Checks.java +++ /dev/null @@ -1,4 +0,0 @@ -package community.icon.cps.score.CPSTreasury.utils; - -public class Checks { -} diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java similarity index 99% rename from CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/CPSTreasury.java rename to CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 57af3a50..bdfdfb8d 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -1,6 +1,6 @@ -package community.icon.cps.score.CPSTreasury; +package community.icon.cps.score.cpstreasury; -import community.icon.cps.score.CPSTreasury.db.ProposalData; +import community.icon.cps.score.cpstreasury.db.ProposalData; import score.*; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; @@ -13,7 +13,7 @@ import java.util.List; import java.util.Map; -import community.icon.cps.score.CPSTreasury.utils.consts; +import community.icon.cps.score.cpstreasury.utils.consts; public class CPSTreasury extends ProposalData{ private static final String TAG = "CPS_Treasury"; diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/db/ProposalData.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java similarity index 98% rename from CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/db/ProposalData.java rename to CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java index 17970b0d..f8525d26 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/db/ProposalData.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java @@ -1,8 +1,7 @@ -package community.icon.cps.score.CPSTreasury.db; +package community.icon.cps.score.cpstreasury.db; -import jdk.jshell.Snippet; import score.*; -import community.icon.cps.score.CPSTreasury.utils.consts; +import community.icon.cps.score.cpstreasury.utils.consts; import java.math.BigInteger; import java.util.Map; diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/ArrayDBUtils.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/ArrayDBUtils.java similarity index 98% rename from CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/ArrayDBUtils.java rename to CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/ArrayDBUtils.java index af84c069..8f09e223 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/ArrayDBUtils.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/ArrayDBUtils.java @@ -1,4 +1,4 @@ -package community.icon.cps.score.CPSTreasury.utils; +package community.icon.cps.score.cpstreasury.utils; import score.Address; import score.ArrayDB; diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/Checks.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/Checks.java new file mode 100644 index 00000000..da8a3fa8 --- /dev/null +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/Checks.java @@ -0,0 +1,4 @@ +package community.icon.cps.score.cpstreasury.utils; + +public class Checks { +} diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/Eventlogs.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/Eventlogs.java similarity index 90% rename from CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/Eventlogs.java rename to CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/Eventlogs.java index 1b8c9306..37ecd221 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/Eventlogs.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/Eventlogs.java @@ -1,4 +1,4 @@ -package community.icon.cps.score.CPSTreasury.utils; +package community.icon.cps.score.cpstreasury.utils; import score.Address; import score.annotation.EventLog; diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/consts.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java similarity index 99% rename from CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/consts.java rename to CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java index 578e05c9..adb5dfc2 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/CPSTreasury/utils/consts.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java @@ -1,4 +1,4 @@ -package community.icon.cps.score.CPSTreasury.utils; +package community.icon.cps.score.cpstreasury.utils; import java.math.BigInteger; diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/BasicTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/BasicTest.java deleted file mode 100644 index c079f05f..00000000 --- a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/BasicTest.java +++ /dev/null @@ -1,73 +0,0 @@ -//package com.iconloop.score.example; -// -//import com.iconloop.score.test.Account; -//import com.iconloop.score.test.Score; -//import com.iconloop.score.test.ServiceManager; -//import com.iconloop.score.test.TestBase; -//import org.junit.jupiter.api.BeforeAll; -//import org.junit.jupiter.api.Test; -// -//import java.math.BigInteger; -// -//import static java.math.BigInteger.TEN; -//import static org.junit.jupiter.api.Assertions.assertEquals; -// -//public class BasicTest extends TestBase { -// private static final String name = "MyIRC2Token"; -// private static final String symbol = "MST"; -// private static final int decimals = 18; -// private static final BigInteger initialSupply = BigInteger.valueOf(1000); -// private static final BigInteger totalSupply = initialSupply.multiply(TEN.pow(decimals)); -// -// private static final ServiceManager sm = getServiceManager(); -// private static final Account owner = sm.createAccount(); -// private static Score tokenScore; -// -// @BeforeAll -// public static void setup() throws Exception{ -// tokenScore = sm.deploy(owner,IRC2BasicToken.class,name,symbol,decimals,initialSupply); -// owner.addBalance(symbol,totalSupply); -// } -// -// @Test -// void name(){ -// assertEquals(name,tokenScore.call("name")); -// } -// -// @Test -// void symbol(){ -// assertEquals(symbol,tokenScore.call("symbol")); -// } -// -// @Test -// void decimals(){ -// assertEquals(decimals,tokenScore.call("decimals")); -// } -// -// @Test -// void totalSupply(){ -// assertEquals(totalSupply,tokenScore.call("totalSupply")); -// } -// -// @Test -// void balanceOf(){ -// assertEquals(owner.getBalance(symbol), -// tokenScore.call("balanceOf",tokenScore.getOwner().getAddress())); -// } -// -// @Test -// void transfer(){ -// Account account1 = sm.createAccount(); -// BigInteger value = TEN.pow(decimals); -// tokenScore.invoke(owner,"transfer",account1.getAddress(),value, "to account1".getBytes()); -// owner.subtractBalance(symbol,value); -// assertEquals(owner.getBalance(symbol), -// tokenScore.call("balanceOf",tokenScore.getOwner().getAddress())); -// assertEquals(value,tokenScore.call("balanceOf",account1.getAddress())); -// -// // transfer self -// tokenScore.invoke(account1,"transfer",account1.getAddress(),value,"self transfer".getBytes()); -// assertEquals(value,tokenScore.call("balanceOf",account1.getAddress())); -// -// } -//} diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/DiceTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/DiceTest.java deleted file mode 100644 index 9e9c587d..00000000 --- a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/DiceTest.java +++ /dev/null @@ -1,186 +0,0 @@ -//package com.iconloop.score.example; -// -//import com.iconloop.score.test.Account; -//import com.iconloop.score.test.Score; -//import com.iconloop.score.test.ServiceManager; -//import com.iconloop.score.test.TestBase; -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.BeforeAll; -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.function.Executable; -//import org.mockito.MockSettings; -//import org.mockito.MockedStatic; -//import org.mockito.Mockito; -//import score.Address; -//import score.Context; -//import score.VarDB; -// -//import javax.xml.crypto.Data; -//import java.math.BigInteger; -// -// -//import static java.math.BigInteger.TEN; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.mockito.Mockito.*; -// -// -//public class DiceTest extends TestBase { -// private static final String name = "DICE"; -// private static final String symbol = "DIC"; -// private static final int decimals = 18; -// private static final BigInteger initialSupply = BigInteger.valueOf(1000); -// private static final Boolean onUdateVar = false; -// private static final BigInteger totalSupply = initialSupply.multiply(TEN.pow(decimals)); -// -// private static final ServiceManager sm = getServiceManager(); -// private static final Account owner = sm.createAccount(); -// private static final Account testAccount = sm.createAccount(); -// private static Score tokenScore; -// private static Dice dicespy; -// -// // final Address scoreAddress = new Address(new byte[Address.LENGTH]); -// -// VarDB
_roulete_score = mock(VarDB.class); -// -// -// -// @BeforeAll -// public static void setup() throws Exception{ -// tokenScore = sm.deploy(owner,Dice.class,onUdateVar); -// owner.addBalance(symbol, totalSupply); -// -// dicespy = (Dice) spy(tokenScore.getInstance()); -// tokenScore.setInstance(dicespy); -// -// } -// -// -// public void bet(Account owner,BigInteger upper,BigInteger lower, String userSeed, BigInteger sideBetAmount, -// String sideBetType){ -// tokenScore.invoke(owner,"set_dice_score",tokenScore.getAddress()); -//// tokenScore.invoke(owner,"set_dice_score","cxe36ce66a334f0ef311cb29d7833ebbfe2637f4e1"); -// tokenScore.invoke(owner,"toggle_game_status"); -// try { -// tokenScore.invoke(owner,"call_bet",upper,lower,userSeed,sideBetAmount,sideBetType); -// } -// -// catch (AssertionError error){ -// throw error; -// } -// } -// -// public void expectErrorMessage(Executable contractCall, String errorMessage) { -// AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); -// assertEquals(errorMessage, e.getMessage()); -// } -// -// @Test -// void toggle_game_status(){ -// assertEquals(false,tokenScore.call("get_game_status")); -// tokenScore.invoke(owner,"toggle_game_status"); -// assertEquals(true,tokenScore.call("get_game_status")); -// } -// -// @DisplayName("Range of upper and lower value") -// @Test -// void upper_and_lower_range_test(){ -// BigInteger upper = BigInteger.valueOf(7); -// BigInteger lower = BigInteger.valueOf(20); -// String userSeed = ""; -// BigInteger sideBetAmount = BigInteger.valueOf(2).multiply(TEN.pow(decimals)); -// String sideBetType = "digits_match"; -// -// Executable upperCall = () -> bet(owner,BigInteger.valueOf(100),lower,userSeed,sideBetAmount,sideBetType); -// String expectedErrorMessage = "Reverted(0): Invalid bet. Choose a number between 0 to 99"; -// expectErrorMessage(upperCall,expectedErrorMessage); -// } -// -// @Test -// void gap_test(){ -// BigInteger upper = BigInteger.valueOf(20); -// BigInteger lower = BigInteger.valueOf(2); -// String userSeed = ""; -// BigInteger sideBetAmount = BigInteger.valueOf(2).multiply(TEN.pow(decimals)); -// String sideBetType = "digits_match"; -// -// Executable upperAndLowerCall = () -> bet(owner,BigInteger.valueOf(99),lower,userSeed,sideBetAmount,sideBetType); -// String expectedErrorMessage = "Reverted(0): Invalid gap. Choose upper and lower values such that gap is between 0 to 95"; -// expectErrorMessage(upperAndLowerCall,expectedErrorMessage); -// -// } -// -// @Test -// void side_bet_test(){ -// BigInteger upper = BigInteger.valueOf(70); -// BigInteger lower = BigInteger.valueOf(20); -// String userSeed = ""; -// BigInteger sideBetAmount = BigInteger.ZERO; -// String sideBetType = "digits_match"; -// -// Executable upperAndLowerCall = () -> bet(owner,BigInteger.valueOf(99),lower,userSeed,sideBetAmount,sideBetType); -// String expectedErrorMessage = "Reverted(0): should set both side bet type as well as side bet amount"; -// expectErrorMessage(upperAndLowerCall,expectedErrorMessage); -// } -// -// -// -// @Test -// void set_score_dice(){ -// Address rouletteScore = Address.fromString("cx00abe8f678c6cf2a5e584b713fbb674a5f342d59"); -// BigInteger amount = BigInteger.valueOf(40); -// -// try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ -// theMock -// .when(() -> Context.newVarDB("roulette_score",Address.class)) -// .thenReturn(_roulete_score); -// } -// Mockito.when(_roulete_score.get()).thenReturn(rouletteScore); -// System.out.println(_roulete_score.get()); -// -// tokenScore.invoke(owner,"set_roulete_score",_roulete_score.get()); -// System.out.println(tokenScore.call("get_roulete_score")); -// } -// -// @Test -// void test_setting_dice_score(){ -// -// tokenScore.invoke(owner,"set_roulete_score",Address.fromString("cx00abe8f678c6cf2a5e584b713fbb674a5f342d59")); -// tokenScore.call("get_roulete_score"); -// } -// -// @DisplayName("Call bet") -// @Test -// void betTest(){ -// -// BigInteger upper = BigInteger.valueOf(70); -// BigInteger lower = BigInteger.valueOf(20); -// String userSeed = "bet"; -// BigInteger sideBetAmount = BigInteger.valueOf(9).multiply(TEN.pow(decimals)); -// String sideBetType = "digits_match"; -// -// // mocking of rouleteScore -// Address rouletteScore = Address.fromString("cx00abe8f678c6cf2a5e584b713fbb674a5f342d59"); -// BigInteger amount = BigInteger.valueOf(40); -// -// doNothing().when(dicespy).takeWager(any()); -// tokenScore.invoke(owner, "toggle_game_status"); -// -// -// -// -// Account alice = sm.createAccount(100); -// BigInteger value = ICX.multiply(BigInteger.valueOf(40)); -// -// sm.transfer(alice, tokenScore.getAddress(), value); -// -// sm.call(owner, value, tokenScore.getAddress(), "call_bet", upper, lower, userSeed, sideBetAmount, sideBetType); -// verify(dicespy).takeWager(value); -// // } //tokenScore.invoke(owner,"call_bet",upper,lower,userSeed,sideBetAmount,sideBetType); -// //sm.call(alice,value,tokenScore.getAddress(),"call_bet",upper,lower,userSeed,sideBetAmount,sideBetType); -// -//// verify(dicespy).call_bet(upper,lower,userSeed,sideBetAmount,sideBetType); -//// verify(dicespy).FundTransfer(alice.getAddress(),value,"Sending icx to Dice score"); -//// assertEquals(value,Account.getAccount(tokenScore.getAddress()).getBalance()); -// } -//} diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2BasicTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2BasicTest.java deleted file mode 100644 index 1dd18302..00000000 --- a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2BasicTest.java +++ /dev/null @@ -1,90 +0,0 @@ -///* -// * Copyright 2020 ICONLOOP Inc. -// * -// * Licensed under the Apache License, Version 2.0 (the "License"); -// * you may not use this file except in compliance with the License. -// * You may obtain a copy of the License at -// * -// * http://www.apache.org/licenses/LICENSE-2.0 -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, -// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// * See the License for the specific language governing permissions and -// * limitations under the License. -// */ -// -//package com.iconloop.score.example; -// -//import com.iconloop.score.test.Account; -//import com.iconloop.score.test.Score; -//import com.iconloop.score.test.ServiceManager; -//import com.iconloop.score.test.TestBase; -//import org.junit.jupiter.api.BeforeAll; -//import org.junit.jupiter.api.Test; -// -//import java.math.BigInteger; -// -//import static java.math.BigInteger.TEN; -//import static org.junit.jupiter.api.Assertions.assertEquals; -// -//class IRC2BasicTest extends TestBase { -// private static final String name = "MyIRC2Token"; -// private static final String symbol = "MIT"; -// private static final int decimals = 18; -// private static final BigInteger initialSupply = BigInteger.valueOf(1000); -// -// private static final BigInteger totalSupply = initialSupply.multiply(TEN.pow(decimals)); -// private static final ServiceManager sm = getServiceManager(); -// private static final Account owner = sm.createAccount(); -// private static Score tokenScore; -// -// @BeforeAll -// public static void setup() throws Exception { -// tokenScore = sm.deploy(owner, IRC2BasicToken2.class, -// name, symbol, decimals, initialSupply); -// owner.addBalance(symbol, totalSupply); -// } -// -// @Test -// void name() { -// assertEquals(name, tokenScore.call("name")); -// } -// -// @Test -// void symbol() { -// assertEquals(symbol, tokenScore.call("symbol")); -// } -// -// @Test -// void decimals() { -// assertEquals(BigInteger.valueOf(decimals), tokenScore.call("decimals")); -// } -// -// @Test -// void totalSupply() { -// assertEquals(totalSupply, tokenScore.call("totalSupply")); -// } -// -// @Test -// void balanceOf() { -// assertEquals(owner.getBalance(symbol), -// tokenScore.call("balanceOf", tokenScore.getOwner().getAddress())); -// } -// -// @Test -// void transfer() { -// Account alice = sm.createAccount(); -// BigInteger value = TEN.pow(decimals); -// tokenScore.invoke(owner, "transfer", alice.getAddress(), value, "to alice".getBytes()); -// owner.subtractBalance(symbol, value); -// assertEquals(owner.getBalance(symbol), -// tokenScore.call("balanceOf", tokenScore.getOwner().getAddress())); -// assertEquals(value, -// tokenScore.call("balanceOf", alice.getAddress())); -// -// // transfer self -// tokenScore.invoke(alice, "transfer", alice.getAddress(), value, "self transfer".getBytes()); -// assertEquals(value, tokenScore.call("balanceOf", alice.getAddress())); -// } -//} diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2BurnableTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2BurnableTest.java deleted file mode 100644 index 94ff7dd8..00000000 --- a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2BurnableTest.java +++ /dev/null @@ -1,92 +0,0 @@ -///* -// * Copyright 2020 ICONLOOP Inc. -// * -// * Licensed under the Apache License, Version 2.0 (the "License"); -// * you may not use this file except in compliance with the License. -// * You may obtain a copy of the License at -// * -// * http://www.apache.org/licenses/LICENSE-2.0 -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, -// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// * See the License for the specific language governing permissions and -// * limitations under the License. -// */ -// -//package com.iconloop.score.example; -// -//import com.iconloop.score.test.Account; -//import com.iconloop.score.test.Score; -//import com.iconloop.score.test.ServiceManager; -//import com.iconloop.score.test.TestBase; -//import org.junit.jupiter.api.BeforeAll; -//import org.junit.jupiter.api.Test; -//import score.Address; -// -//import java.math.BigInteger; -// -//import static java.math.BigInteger.TEN; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.mockito.Mockito.spy; -//import static org.mockito.Mockito.verify; -// -//public class IRC2BurnableTest extends TestBase { -// private static final String name = "MyIRC2Burnable"; -// private static final String symbol = "MIB"; -// private static final int decimals = 18; -// private static final BigInteger initialSupply = BigInteger.valueOf(1000); -// -// private static BigInteger totalSupply = initialSupply.multiply(TEN.pow(decimals)); -// private static final ServiceManager sm = getServiceManager(); -// private static final Account owner = sm.createAccount(); -// private static Score tokenScore; -// private static IRC2BurnableToken tokenSpy; -// -// @BeforeAll -// public static void setup() throws Exception { -// tokenScore = sm.deploy(owner, IRC2BurnableToken.class, -// name, symbol, decimals, initialSupply); -// owner.addBalance(symbol, totalSupply); -// -// // setup spy object against the tokenScore object -// tokenSpy = (IRC2BurnableToken) spy(tokenScore.getInstance()); -// tokenScore.setInstance(tokenSpy); -// } -// -// @Test -// void burn() { -// final Address zeroAddress = new Address(new byte[Address.LENGTH]); -// Account alice = sm.createAccount(); -// alice.addBalance(symbol, transferToken(owner, alice, TEN)); -// assertEquals(totalSupply, tokenScore.call("totalSupply")); -// -// // burn one token -// BigInteger amount = TEN.pow(decimals); -// tokenScore.invoke(alice, "burn", amount); -// alice.subtractBalance(symbol, amount); -// totalSupply = totalSupply.subtract(amount); -// assertEquals(alice.getBalance(symbol), tokenScore.call("balanceOf", alice.getAddress())); -// assertEquals(totalSupply, tokenScore.call("totalSupply")); -// verify(tokenSpy).Transfer(alice.getAddress(), zeroAddress, amount, "burn".getBytes()); -// -// // burn all the tokens -// amount = (BigInteger) tokenScore.call("balanceOf", alice.getAddress()); -// tokenScore.invoke(alice, "burn", amount); -// totalSupply = totalSupply.subtract(amount); -// assertEquals(BigInteger.ZERO, tokenScore.call("balanceOf", alice.getAddress())); -// assertEquals(totalSupply, tokenScore.call("totalSupply")); -// verify(tokenSpy).Transfer(alice.getAddress(), zeroAddress, amount, "burn".getBytes()); -// } -// -// BigInteger transferToken(Account from, Account to, BigInteger tokenAmount) { -// BigInteger value = TEN.pow(decimals).multiply(tokenAmount); -// tokenScore.invoke(from, "transfer", to.getAddress(), value, "data".getBytes()); -// from.subtractBalance(symbol, value); -// assertEquals(from.getBalance(symbol), -// tokenScore.call("balanceOf", from.getAddress())); -// assertEquals(value, -// tokenScore.call("balanceOf", to.getAddress())); -// return value; -// } -//} diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2CappedTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2CappedTest.java deleted file mode 100644 index 8a27d2c9..00000000 --- a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2CappedTest.java +++ /dev/null @@ -1,124 +0,0 @@ -//package com.iconloop.score.example; -// -//import com.iconloop.score.test.Account; -//import com.iconloop.score.test.Score; -//import com.iconloop.score.test.ServiceManager; -//import com.iconloop.score.test.TestBase; -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.BeforeAll; -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.function.Executable; -//import score.Address; -// -//import java.math.BigInteger; -// -//import static java.math.BigInteger.TEN; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.mockito.Mockito.spy; -//import static org.mockito.Mockito.verify; -// -//public class IRC2CappedTest extends TestBase { -// private static final String name = "Capped"; -// private static final String symbol = "CAP"; -// private static final int decimals = 18; -// private static final BigInteger initialSupply = BigInteger.valueOf(1000); -// private static final BigInteger capped = BigInteger.valueOf(1000000); -// -// private static BigInteger totalSupply = initialSupply.multiply(TEN.pow(decimals)); -// private static final ServiceManager sm = getServiceManager(); -// private static final Account owner = sm.createAccount(); -// private static final Account testAccount = sm.createAccount(); -// private static Score tokenScore; -// private static IRC2CappedToken tokenSpy; -// -// -// @BeforeAll -// public static void setup() throws Exception{ -// tokenScore = sm.deploy(owner, -// IRC2CappedToken.class,name,symbol,decimals,initialSupply,capped); -// owner.addBalance(symbol,totalSupply); -// -// tokenSpy = (IRC2CappedToken) spy(tokenScore.getInstance()); -// tokenScore.setInstance(tokenSpy); -// } -// -// public void mint(Account owner, BigInteger amount){ -// try { -// tokenScore.invoke(owner,"mint",amount); -// } -// catch (AssertionError error){ -// throw error; -// } -// } -// -// public void mintTo(Address caller, BigInteger amount){ -// try { -// tokenScore.invoke(owner,"mintTo",caller,amount); -// } -// catch (AssertionError error){ -// throw error; -// } -// } -// -// public void expectErrorMessage(Executable contractCall, String errorMessage) { -// AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); -// assertEquals(errorMessage, e.getMessage()); -// } -// -// @DisplayName("Mint token by owner") -// @Test -// void mint_by_owner(){ -// final Address zeroAddress = new Address(new byte[Address.LENGTH]); -// BigInteger amount = TEN.pow(decimals); -// tokenScore.invoke(owner,"mint",amount); -// owner.addBalance(symbol,amount); -// assertEquals(owner.getBalance(symbol),tokenScore.call("balanceOf",owner.getAddress())); -// totalSupply = totalSupply.add(amount); -// assertEquals(totalSupply,tokenScore.call("totalSupply")); -// verify(tokenSpy).Transfer(zeroAddress,owner.getAddress(),amount,"mint".getBytes()); -// -// } -// -// @DisplayName("Mint token by other accounts exceeding cap limit") -// @Test -// void mint_exceed_capped_token(){ -// BigInteger amount = BigInteger.valueOf(1000000000).pow(decimals); -// Executable mintExceedCapCaller = () ->mint(testAccount,amount); -// String expectedErrorMessage = "Only owner can mint tokens"; -// expectErrorMessage(mintExceedCapCaller,expectedErrorMessage); -// } -// -// @DisplayName("Mint token by owner exceeding cap limit ") -// @Test -// void mint_exceed_capped_token_by_owner(){ -// BigInteger amount = BigInteger.valueOf(1000000000).pow(decimals); -// Executable mintExceedCapCaller = () ->mint(owner,amount); -// String expectedErrorMessage = "Cap:capped exceeded"; -// expectErrorMessage(mintExceedCapCaller,expectedErrorMessage); -// } -// -// @DisplayName("Mint to another address by owner") -// @Test -// void mintTo_by_owner(){ -// final Address zeroAddress = new Address(new byte[Address.LENGTH]); -// BigInteger amount = TEN.pow(decimals); -// tokenScore.invoke(owner,"mintTo", testAccount.getAddress(),amount); -// -// testAccount.addBalance(symbol,amount); -// assertEquals(testAccount.getBalance(symbol),tokenScore.call("balanceOf",testAccount.getAddress())); -// verify(tokenSpy).Transfer(zeroAddress,testAccount.getAddress(),amount,"mint".getBytes()); -// } -// -// @DisplayName("Mint to another address by owner exceeding cap limit") -// @Test -// void mintTo_capped_exceed_by_owner(){ -// BigInteger amount = BigInteger.valueOf(1000000000).pow(decimals); -// // tokenScore.invoke(owner,"mintTo", testAccount.getAddress(),amount); -// Executable mintToExceedCapCaller = () ->mintTo(testAccount.getAddress(),amount); -// String expectedErrorMessage = "Cap:capped exceeded"; -// expectErrorMessage(mintToExceedCapCaller,expectedErrorMessage); -// -// } -// -//} diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2MintableTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2MintableTest.java deleted file mode 100644 index 625aa124..00000000 --- a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2MintableTest.java +++ /dev/null @@ -1,133 +0,0 @@ -//package com.iconloop.score.example; -// -//import com.iconloop.score.test.Account; -//import com.iconloop.score.test.Score; -//import com.iconloop.score.test.ServiceManager; -//import com.iconloop.score.test.TestBase; -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.BeforeAll; -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.function.Executable; -//import score.Address; -// -//import java.math.BigInteger; -// -//import static java.math.BigInteger.*; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.mockito.Mockito.spy; -//import static org.mockito.Mockito.verify; -// -//public class IRC2MintableTest extends TestBase { -// private static final String name = "Mintable"; -// private static final String symbol = "MIT"; -// private static final int decimals = 18; -// private static final BigInteger initialSupply = BigInteger.valueOf(1000); -// private static BigInteger totalSupply = initialSupply.multiply(TEN.pow(decimals)); -// -// private static final ServiceManager sm = getServiceManager(); -// private static final Account owner = sm.createAccount(); -// private static final Account testAccount = sm.createAccount(); -// private static Score tokenScore; -// private static IRC2MintableToken tokenSpy; -// -// @BeforeAll -// public static void setup() throws Exception{ -// tokenScore = sm.deploy(owner, IRC2MintableToken.class, -// name, symbol, decimals, initialSupply); -// owner.addBalance(symbol,totalSupply); -// -// tokenSpy = (IRC2MintableToken) spy(tokenScore.getInstance()); -// tokenScore.setInstance(tokenSpy); -// } -// -// public void mint(Account owner, BigInteger amount){ -// try { -// tokenScore.invoke(owner,"mint",amount); -// } -// catch (AssertionError error){ -// throw error; -// } -// } -// -// public void isMinter(Address minter){ -// try { -// tokenScore.call("isMinter",minter); -// } -// catch (AssertionError error){ -// throw error; -// } -// } -// -// public void setMinter(Account test,Address minter){ -// try { -// tokenScore.invoke(test,"setMinter",minter); -// } -// catch (AssertionError error){ -// throw (error); -// } -// } -// -// public void expectErrorMessage(Executable contractCall, String errorMessage) { -// AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); -// assertEquals(errorMessage, e.getMessage()); -// } -// -// @DisplayName("Minting new tokens") -// @Test -// void mint_test_by_owner(){ -// final Address zeroAddress = new Address(new byte[Address.LENGTH]); -// BigInteger amount = TEN.pow(decimals); -// tokenScore.invoke(owner,"mint",amount); -// -// owner.addBalance(symbol,amount); -// assertEquals(owner.getBalance(symbol),tokenScore.call("balanceOf",owner.getAddress())); -// -// totalSupply = totalSupply.add(amount); -// assertEquals(totalSupply,tokenScore.call("totalSupply")); -// -// verify(tokenSpy).Transfer(zeroAddress,owner.getAddress(),amount,"mint".getBytes()); -// } -// -// @DisplayName("Trying to mint token by other account") -// @Test -// void mint_test(){ -// BigInteger amount = TEN.pow(decimals); -// Executable mintNotByOwnerCall = () -> mint(testAccount,amount); -// String expectedErrorMessage = "Mint: minters or owners can only mint new tokens"; -// expectErrorMessage(mintNotByOwnerCall,expectedErrorMessage); -// -// } -// -// @DisplayName("Minting tokens to others address") -// @Test -// void mintTo_test(){ -// final Address zeroAddress = new Address(new byte[Address.LENGTH]); -// BigInteger amount = TEN.pow(decimals); -// tokenScore.invoke(owner,"mintTo",testAccount.getAddress(),amount); -// -// testAccount.addBalance(symbol,amount); -// assertEquals(testAccount.getBalance(symbol),tokenScore.call("balanceOf",testAccount.getAddress())); -// -// totalSupply = totalSupply.add(amount); -// assertEquals(totalSupply,tokenScore.call("totalSupply")); -// verify(tokenSpy).Transfer(zeroAddress,testAccount.getAddress(),amount,"mint".getBytes()); -// } -// -// @DisplayName("Setting minter by owner") -// @Test -// void set_minter_test_by_owner(){ -// tokenScore.invoke(owner,"setMinter",testAccount.getAddress()); -// assertEquals(testAccount.getAddress(),tokenScore.call("getMinter")); -// } -// -// @DisplayName("Setting minter by another account/ not by owner") -// @Test -// void set_minter(){ -// Executable setMinterByOwnerCall = () -> setMinter(testAccount,owner.getAddress()); -// String expectedErrorMessage = "Minter: only owners can set minters"; -// expectErrorMessage(setMinterByOwnerCall,expectedErrorMessage); -// } -// -// -//} diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2PausableTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2PausableTest.java deleted file mode 100644 index 029af41c..00000000 --- a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/IRC2PausableTest.java +++ /dev/null @@ -1,125 +0,0 @@ -//package com.iconloop.score.example; -// -//import com.iconloop.score.test.Account; -//import com.iconloop.score.test.Score; -//import com.iconloop.score.test.ServiceManager; -//import com.iconloop.score.test.TestBase; -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.BeforeAll; -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.function.Executable; -//import score.Address; -// -//import java.math.BigInteger; -//import static java.math.BigInteger.TEN; -// -//import static org.mockito.Mockito.spy; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.mockito.Mockito.verify; -// -//public class IRC2PausableTest extends TestBase { -// private static final String name ="Pausable"; -// private static final String symbol = "PAS"; -// private static final int decimals = 18; -// private static final BigInteger initialSupply = BigInteger.valueOf(1000); -// private static final BigInteger totalSupply = initialSupply.multiply(BigInteger.TEN.pow(decimals)); -// -// private static final ServiceManager sm = getServiceManager(); -// private static final Account owner = sm.createAccount(); -// private static final Account testAccount = sm.createAccount(); -// private static Score tokenScore; -// private static IRC2PausableToken tokenSpy; -// -// @BeforeAll -// public static void setup() throws Exception{ -// tokenScore = sm.deploy(owner,IRC2PausableToken.class, -// name,symbol,decimals,initialSupply); -// owner.addBalance(symbol,totalSupply); -// -// tokenSpy = (IRC2PausableToken) spy(tokenScore.getInstance()); -// tokenScore.setInstance(tokenSpy); -// } -// -// public void transfer(Address address, BigInteger amount){ -// -// try { -// tokenScore.invoke(owner,"transfer",address,amount,"transfer".getBytes()); -// } -// catch (AssertionError error){ -// throw error; -// } -// } -// -// public void expectErrorMessage(Executable contractCall, String errorMessage) { -// AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); -// assertEquals(errorMessage, e.getMessage()); -// } -// -// @DisplayName("set pause status") -// @Test -// void set_pause(){ -// tokenScore.invoke(owner,"setPause",true); -// assertEquals(true,tokenScore.call("setPause",true)); -// -// tokenScore.invoke(owner,"setPause", false); -// assertEquals(false,tokenScore.call("setPause",false)); -// } -// -// @DisplayName("get pause status") -// @Test -// void get_pause(){ -// // setting value false -// tokenScore.invoke(owner,"setPause",false); -// assertEquals(false,tokenScore.call("getPause")); -// -// // setting value true -// tokenScore.invoke(owner,"setPause",true); -// assertEquals(true,tokenScore.call("getPause")); -// } -// -// @DisplayName("pause contract") -// @Test -// void pause_contract(){ -// tokenScore.invoke(owner,"pause"); -// assertEquals(true,tokenScore.call("getPause")); -// } -// -// @DisplayName("unpause contract") -// @Test -// void unpause_contract(){ -// tokenScore.invoke(owner,"unpause"); -// assertEquals(false,tokenScore.call("getPause")); -// } -// -// @DisplayName("token transfer when contract is not paused") -// @Test -// void transfer_when_not_paused(){ -// // contract not paused -// BigInteger amount = TEN.pow(decimals); -// System.out.println(amount); -// tokenScore.invoke(owner,"transfer",testAccount.getAddress(), amount, "transfer".getBytes()); -// -// testAccount.addBalance(symbol,amount); -// assertEquals(testAccount.getBalance(symbol),tokenScore.call("balanceOf",testAccount.getAddress())); -// -// owner.subtractBalance(symbol,amount); -// assertEquals(owner.getBalance(symbol),tokenScore.call("balanceOf",owner.getAddress())); -// -// verify(tokenSpy).Transfer(owner.getAddress(),testAccount.getAddress(),amount,"transfer".getBytes()); -// -// } -// -// @DisplayName("token transfer when contract is paused") -// @Test -// void transfer_when_paused(){ -// BigInteger amount = TEN.pow(decimals); -// -// tokenScore.invoke(owner,"setPause",true); -// -// Executable transfer_when_paused_call= () -> transfer(testAccount.getAddress(),amount); -// String expectedErrorMessage = "Transfer: Paused token can not be transferred"; -// expectErrorMessage(transfer_when_paused_call,expectedErrorMessage); -// -// } -//} diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java similarity index 96% rename from CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/CPSTreasuryTest.java rename to CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index 1f36a1f8..5e1095d2 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/CPSTreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -1,5 +1,4 @@ -package community.icon.cps.score.CPSTreasury; -import com.eclipsesource.json.JsonObject; +package community.icon.cps.score.cpstreasury; import com.iconloop.score.test.Account; import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; @@ -8,19 +7,13 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; -import org.mockito.Answers; -import org.mockito.MockedStatic; import org.mockito.Mockito; import score.Address; -import score.Context; import score.DictDB; import score.VarDB; import java.math.BigInteger; import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; From 9614f17008487ee5c114965e5378b20422f55bd8 Mon Sep 17 00:00:00 2001 From: ibriz Date: Tue, 26 Apr 2022 12:33:02 +0545 Subject: [PATCH 016/112] fetched with get methods --- .../cps/score/cpstreasury/CPSTreasury.java | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index bdfdfb8d..145971be 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -298,11 +298,7 @@ public void send_installment_to_contributor(String _ipfs_key){ BigInteger installmentAmount = BigInteger.ZERO; String prefix = proposalPrefix(_ipfs_key); Map proposalData = getDataFromProposalDB(prefix); -// int installmentCount = ProposalData.installmentCount.at(prefix).getOrDefault(0); -// BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); -// BigInteger remainingAmount = ProposalData.remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); -// Address contributorAddress = ProposalData.contributorAddress.at(prefix).get(); -// String flag = ProposalData.token.at(prefix).get(); + int installmentCount = (int) proposalData.get(consts.INSTALLMENT_COUNT); BigInteger withdrawAmount = (BigInteger) proposalData.get(consts.WITHDRAW_AMOUNT); BigInteger remainingAmount = (BigInteger) proposalData.get(consts.REMAINING_AMOUNT); @@ -320,12 +316,12 @@ public void send_installment_to_contributor(String _ipfs_key){ // ProposalData.remainingAmount.at(prefix).set(remainingAmount.subtract(installmentAmount)); // ProposalData.withdrawAmount.at(prefix).set(withdrawAmount.add(installmentAmount)); - setInstallmentCount(prefix, newInstallmentCount); - setRemainingAmount(prefix, remainingAmount.subtract(installmentAmount)); - setWithdrawAmount(prefix, withdrawAmount.add(installmentAmount)); - installmentFundRecord.at(contributorAddress.toString()).set(flag, - installmentFundRecord.at(contributorAddress.toString()).get(flag).add(installmentAmount)); - ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); + setInstallmentCount(prefix, newInstallmentCount); + setRemainingAmount(prefix, remainingAmount.subtract(installmentAmount)); + setWithdrawAmount(prefix, withdrawAmount.add(installmentAmount)); + installmentFundRecord.at(contributorAddress.toString()).set(flag, + installmentFundRecord.at(contributorAddress.toString()).get(flag).add(installmentAmount)); + ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); if (newInstallmentCount == 0){ // ProposalData.status.at(prefix).set(COMPLETED); @@ -344,12 +340,6 @@ public void send_reward_to_sponsor(String _ipfs_key){ Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); BigInteger installmentAmount = BigInteger.ZERO; String prefix = proposalPrefix(_ipfs_key); -// Map proposalData = getDataFromProposalDB(prefix); -// int sponsorRewardCount = ProposalData.sponsorRewardCount.at(prefix).getOrDefault(0); -// BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); -// BigInteger sponsorRemainingAmount = ProposalData.sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); -// Address sponsorAddress = ProposalData.sponsorAddress.at(prefix).get(); -// String flag = ProposalData.token.at(prefix).get(); int sponsorRewardCount = getSponsorRewardCount(prefix); BigInteger sponsorWithdrawAmount = getSponsorWithdrawAmount(prefix); @@ -368,16 +358,12 @@ public void send_reward_to_sponsor(String _ipfs_key){ // ProposalData.sponsorWithdrawAmount.at(prefix).set(sponsorWithdrawAmount.add(installmentAmount)); // ProposalData.sponsorRemainingAmount.at(prefix).set(sponsorRemainingAmount.subtract(installmentAmount)); - setSponsorRewardCount(prefix, newSponsorRewardCount); - setSponsorWithdrawAmount(prefix, sponsorWithdrawAmount.add(installmentAmount)); - setSponsorRemainingAmount(prefix, sponsorRemainingAmount.subtract(installmentAmount)); - installmentFundRecord.at(sponsorAddress.toString()).set(flag, installmentFundRecord.at(sponsorAddress.toString()).get(flag).add(installmentAmount)); - ProposalFundSent(sponsorAddress, "New installment " + installmentAmount + " " + - flag + " sent to sponsor address."); - } - catch (Exception e){ - Context.revert(TAG + ": Network problem. Sending project funds to sponsor."); - } + setSponsorRewardCount(prefix, newSponsorRewardCount); + setSponsorWithdrawAmount(prefix, sponsorWithdrawAmount.add(installmentAmount)); + setSponsorRemainingAmount(prefix, sponsorRemainingAmount.subtract(installmentAmount)); + installmentFundRecord.at(sponsorAddress.toString()).set(flag, installmentFundRecord.at(sponsorAddress.toString()).get(flag).add(installmentAmount)); + ProposalFundSent(sponsorAddress, "New installment " + installmentAmount + " " + + flag + " sent to sponsor address."); } @External From 47821ade1fd3827fa4d829d5a7f29a07454c07af Mon Sep 17 00:00:00 2001 From: ibriz Date: Tue, 26 Apr 2022 12:33:15 +0545 Subject: [PATCH 017/112] Linter fix --- .../cps/score/cpstreasury/CPSTreasury.java | 191 ++++++++---------- 1 file changed, 82 insertions(+), 109 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 145971be..cc2e5968 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -15,7 +15,7 @@ import community.icon.cps.score.cpstreasury.utils.consts; -public class CPSTreasury extends ProposalData{ +public class CPSTreasury extends ProposalData { private static final String TAG = "CPS_Treasury"; private static final String PROPOSAL_DB_PREFIX = "proposal"; @@ -58,57 +58,58 @@ public class CPSTreasury extends ProposalData{ private final VarDB
cpsScore = Context.newVarDB(CPS_SCORE, Address.class); private final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); - public CPSTreasury(){ + public CPSTreasury() { } @External(readonly = true) - public String name(){ + public String name() { return TAG; } + @Payable - public void fallback(){ + public void fallback() { Context.revert(TAG + ": ICX can only be send by CPF Treasury Score"); } - private void setId(String _val){ + private void setId(String _val) { id.set(_val); } - private String getId(){ + private String getId() { return id.get(); } - private String proposalPrefix(String _proposal_key){ + private String proposalPrefix(String _proposal_key) { return PROPOSAL_DB_PREFIX + "|" + id.get() + "|" + _proposal_key; } - private Boolean proposalExists(String _ipfs_key){ + private Boolean proposalExists(String _ipfs_key) { return proposalsKeyListIndex.getOrDefault(_ipfs_key, null) != null; } - private void validateAdmins(){ + private void validateAdmins() { Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "is_admin", Context.getCaller()); Context.require(isAdmin, TAG + ": Only admins can call this method"); } - private void validateAdminScore(Address _score){ + private void validateAdminScore(Address _score) { validateAdmins(); Context.require(_score.isContract(), TAG + "Target " + _score + " is not a score."); } - private void validateCpsScore(){ + private void validateCpsScore() { Context.require(Context.getCaller().equals(cpsScore.get()), TAG + ": Only CPS score " + cpsScore.get() + " can send fund using this method."); } - private void validateCpfTreasuryScore(){ + private void validateCpfTreasuryScore() { Context.require(Context.getCaller().equals(cpfTreasuryScore.get()), TAG + ": Only CPF Treasury score " + cpfTreasuryScore.get() + " can send fund using this method."); } - private void addRecord(ProposalData.ProposalAttributes _proposal){ + private void addRecord(ProposalData.ProposalAttributes _proposal) { ProposalData proposalData = new ProposalData(); String ipfs_hash = _proposal.ipfs_hash; Context.require(!proposalExists(ipfs_hash), TAG + ": Already have this project"); @@ -117,58 +118,58 @@ private void addRecord(ProposalData.ProposalAttributes _proposal){ proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); } - private Map getProjects(String _proposal_key){ + private Map getProjects(String _proposal_key) { ProposalData proposalData = new ProposalData(); return proposalData.getDataFromProposalDB(_proposal_key); } @External - public void setCpsScore(Address _score){ + public void setCpsScore(Address _score) { validateAdminScore(_score); cpsScore.set(_score); } @External(readonly = true) - public Address getCpsScore(){ + public Address getCpsScore() { return cpsScore.get(); } @External - public void setCpfTreasuryScore(Address _score){ + public void setCpfTreasuryScore(Address _score) { validateAdminScore(_score); cpfTreasuryScore.set(_score); } @External(readonly = true) - public Address getCpfTreasuryScore(){ + public Address getCpfTreasuryScore() { return cpfTreasuryScore.get(); } @External - public void setBnUSDScore(Address _score){ + public void setBnUSDScore(Address _score) { validateAdminScore(_score); balancedDollar.set(_score); } @External - public Address getBnUSDScore(){ + public Address getBnUSDScore() { return balancedDollar.get(); } @External(readonly = true) - public Map get_contributor_projected_fund(Address _wallet_address){ + public Map get_contributor_projected_fund(Address _wallet_address) { ProposalData proposalData = new ProposalData(); BigInteger totalAmountToBePaidICX = BigInteger.ZERO; BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; List> projectDetails = new ArrayList<>(); - for (int i = 0; i < proposalsKeys.size(); i++){ + for (int i = 0; i < proposalsKeys.size(); i++) { String _ipfs_key = proposalsKeys.get(i); Map proposal_details = proposalData.getDataFromProposalDB(_ipfs_key); - if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)){ - if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())){ + if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { + if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); int totalPaidCount = (int) proposal_details.get(consts.INSTALLMENT_COUNT); - if (totalPaidCount < totalInstallment){ + if (totalPaidCount < totalInstallment) { String flag = (String) proposal_details.get(consts.TOKEN); BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); @@ -183,10 +184,9 @@ public Address getBnUSDScore(){ consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)).toString()); projectDetails.add(project_details); - if (flag.equals(consts.ICX)){ + if (flag.equals(consts.ICX)) { totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - } - else { + } else { totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); } } @@ -203,21 +203,21 @@ public Address getBnUSDScore(){ @External(readonly = true) - public Map get_sponsor_projected_fund(Address _wallet_address){ + public Map get_sponsor_projected_fund(Address _wallet_address) { ProposalData proposalData = new ProposalData(); BigInteger totalAmountToBePaidICX = BigInteger.ZERO; BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; BigInteger totalSponsorBondICX = BigInteger.ZERO; BigInteger totalSponsorBondbnUSD = BigInteger.ZERO; List> projectDetails = new ArrayList<>(); - for (int i = 0; i < proposalsKeys.size(); i++){ + for (int i = 0; i < proposalsKeys.size(); i++) { String _ipfs_key = proposalsKeys.get(i); Map proposal_details = proposalData.getDataFromProposalDB(_ipfs_key); - if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)){ - if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())){ + if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { + if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); int totalPaidCount = (int) proposal_details.get(consts.INSTALLMENT_COUNT); - if (totalPaidCount < totalInstallment){ + if (totalPaidCount < totalInstallment) { String flag = (String) proposal_details.get(consts.TOKEN); BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); @@ -234,11 +234,10 @@ public Address getBnUSDScore(){ consts.SPONSOR_BOND_AMOUNT, depositedSponsorBond.toString()); projectDetails.add(project_details); - if (flag.equals(consts.ICX)){ + if (flag.equals(consts.ICX)) { totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); totalSponsorBondICX = totalSponsorBondICX.add(depositedSponsorBond); - } - else { + } else { totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); totalSponsorBondbnUSD = totalSponsorBondbnUSD.add(depositedSponsorBond); } @@ -256,7 +255,7 @@ public Address getBnUSDScore(){ ); } - private void depositProposalFund(ProposalData.ProposalAttributes _proposals, BigInteger _value){ + private void depositProposalFund(ProposalData.ProposalAttributes _proposals, BigInteger _value) { addRecord(_proposals); ProposalFundDeposited(_proposals.ipfs_hash, "Received " + _proposals.ipfs_hash + " " + _value + " " + consts.bnUSD + " fund from CPF"); @@ -265,7 +264,7 @@ private void depositProposalFund(ProposalData.ProposalAttributes _proposals, Big @External @Payable public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, BigInteger _added_sponsor_reward, - int _added_installment_count){ + int _added_installment_count) { ProposalData proposalData = new ProposalData(); Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS hash."); String proposalPrefix = proposalPrefix(_ipfs_key); @@ -285,14 +284,14 @@ public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, Big setRemainingAmount(proposalPrefix, remainingAmount.add(_added_budget)); setSponsorRemainingAmount(proposalPrefix, sponsorRemainingAmount.add(_added_sponsor_reward)); setInstallmentCount(proposalPrefix, installmentCount + _added_installment_count); - setSponsorRewardCount(proposalPrefix, sponsorRewardCount+ _added_installment_count); + setSponsorRewardCount(proposalPrefix, sponsorRewardCount + _added_installment_count); ProposalFundDeposited(_ipfs_key, _ipfs_key + ": Added Budget: " + _added_budget + " " + flag + "and Added time: " + _added_installment_count + " Successfully"); } @External - public void send_installment_to_contributor(String _ipfs_key){ + public void send_installment_to_contributor(String _ipfs_key) { validateCpsScore(); Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); BigInteger installmentAmount = BigInteger.ZERO; @@ -305,16 +304,12 @@ public void send_installment_to_contributor(String _ipfs_key){ Address contributorAddress = (Address) proposalData.get(consts.CONTRIBUTOR_ADDRESS); String flag = (String) proposalData.get(consts.TOKEN); - try { - if (installmentCount == 1) { - installmentAmount = remainingAmount; - } else { - installmentAmount = remainingAmount.divide(BigInteger.valueOf(installmentCount)); - } - int newInstallmentCount = installmentCount - 1; -// ProposalData.installmentCount.at(prefix).set(newInstallmentCount); -// ProposalData.remainingAmount.at(prefix).set(remainingAmount.subtract(installmentAmount)); -// ProposalData.withdrawAmount.at(prefix).set(withdrawAmount.add(installmentAmount)); + if (installmentCount == 1) { + installmentAmount = remainingAmount; + } else { + installmentAmount = remainingAmount.divide(BigInteger.valueOf(installmentCount)); + } + int newInstallmentCount = installmentCount - 1; setInstallmentCount(prefix, newInstallmentCount); setRemainingAmount(prefix, remainingAmount.subtract(installmentAmount)); @@ -323,18 +318,13 @@ public void send_installment_to_contributor(String _ipfs_key){ installmentFundRecord.at(contributorAddress.toString()).get(flag).add(installmentAmount)); ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); - if (newInstallmentCount == 0){ -// ProposalData.status.at(prefix).set(COMPLETED); - setStatus(prefix, COMPLETED); - } - } - catch (Exception e){ - Context.revert(TAG + ": Network problem. Sending project funds to contributor. " + e); + if (newInstallmentCount == 0) { + setStatus(prefix, COMPLETED); } } @External - public void send_reward_to_sponsor(String _ipfs_key){ + public void send_reward_to_sponsor(String _ipfs_key) { validateCpsScore(); Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); @@ -347,16 +337,12 @@ public void send_reward_to_sponsor(String _ipfs_key){ Address sponsorAddress = getSponsorAddress(prefix); String flag = getToken(prefix); - try { - if (sponsorRewardCount == 1) { - installmentAmount = sponsorRemainingAmount; - } else { - installmentAmount = sponsorRemainingAmount.divide(BigInteger.valueOf(sponsorRewardCount)); - } - int newSponsorRewardCount = sponsorRewardCount - 1; -// ProposalData.sponsorRewardCount.at(prefix).set(newSponsorRewardCount); -// ProposalData.sponsorWithdrawAmount.at(prefix).set(sponsorWithdrawAmount.add(installmentAmount)); -// ProposalData.sponsorRemainingAmount.at(prefix).set(sponsorRemainingAmount.subtract(installmentAmount)); + if (sponsorRewardCount == 1) { + installmentAmount = sponsorRemainingAmount; + } else { + installmentAmount = sponsorRemainingAmount.divide(BigInteger.valueOf(sponsorRewardCount)); + } + int newSponsorRewardCount = sponsorRewardCount - 1; setSponsorRewardCount(prefix, newSponsorRewardCount); setSponsorWithdrawAmount(prefix, sponsorWithdrawAmount.add(installmentAmount)); @@ -367,18 +353,12 @@ public void send_reward_to_sponsor(String _ipfs_key){ } @External - public void disqualify_project(String _ipfs_key){ + public void disqualify_project(String _ipfs_key) { validateCpsScore(); Context.require(proposalExists(_ipfs_key), TAG + ": Project not found. Invalid IPFS hash."); String prefix = proposalPrefix(_ipfs_key); setStatus(prefix, DISQUALIFIED); -// BigInteger totalBudget = ProposalData.totalBudget.at(prefix).getOrDefault(BigInteger.ZERO); -// BigInteger withdrawAmount = ProposalData.withdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); -// BigInteger sponsorReward = ProposalData.sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO); -// BigInteger sponsorWithdrawAmount = ProposalData.sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO); -// String flag = ProposalData.token.at(prefix).get(); - BigInteger totalBudget = getTotalBudget(prefix); BigInteger withdrawAmount = getWithdrawAmount(prefix); BigInteger sponsorReward = getSponsorReward(prefix); @@ -409,40 +389,28 @@ else if(flag.equals(consts.bnUSD)){ } @External - public void claim_reward(){ + public void claim_reward() { BigInteger availableAmountICX = installmentFundRecord.at(Context.getCaller().toString()).get(consts.ICX); BigInteger availableAmountbnUSD = installmentFundRecord.at(Context.getCaller().toString()).get(consts.bnUSD); - if (availableAmountICX.compareTo(BigInteger.ZERO) > 0){ - try{ - installmentFundRecord.at(Context.getCaller().toString()).set(consts.ICX, BigInteger.ZERO); - Context.transfer(Context.getCaller(), availableAmountICX); - ProposalFundWithdrawn(Context.getCaller(), availableAmountICX + " " + consts.ICX + " withdrawn to " + Context.getCaller()); - } - catch (Exception e){ - Context.revert(TAG + ": Network problem while claiming reward."); - } - } - else if(availableAmountbnUSD.compareTo(BigInteger.ZERO) > 0){ - try { - installmentFundRecord.at(Context.getCaller().toString()).set(consts.bnUSD, BigInteger.ZERO); - callScore(balancedDollar.get(), "transfer",Context.getCaller(), availableAmountbnUSD); - } - catch (Exception e){ - Context.revert(TAG + ": Network problem while claiming reward."); - } - } - else{ + if (availableAmountICX.compareTo(BigInteger.ZERO) > 0) { + installmentFundRecord.at(Context.getCaller().toString()).set(consts.ICX, BigInteger.ZERO); + Context.transfer(Context.getCaller(), availableAmountICX); + ProposalFundWithdrawn(Context.getCaller(), availableAmountICX + " " + consts.ICX + " withdrawn to " + Context.getCaller()); + } else if (availableAmountbnUSD.compareTo(BigInteger.ZERO) > 0) { + installmentFundRecord.at(Context.getCaller().toString()).set(consts.bnUSD, BigInteger.ZERO); + callScore(balancedDollar.get(), "transfer", Context.getCaller(), availableAmountbnUSD); + } else { Context.revert(TAG + ": Claim Reward Fails. Available amount(ICX) = " + availableAmountICX + " and Available amount(bnUSD) = " + availableAmountbnUSD); } } @External - public void tokenFallback(Address _from, BigInteger _value, byte[] _data){ + public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { Context.require(_from.equals(cpfTreasuryScore.get()), TAG + "Only receiving from " + cpfTreasuryScore.get()); String unpacked_data = new String(_data); JsonObject jsonObject = Json.parse(unpacked_data).asObject(); JsonObject params = jsonObject.get("params").asObject(); - if (jsonObject.get("method").asString().equals("deposit_proposal_fund")){ + if (jsonObject.get("method").asString().equals("deposit_proposal_fund")) { String ipfs_hash = params.get("ipfs_hash").asString(); int project_duration = Integer.parseInt(params.get("project_duration").asString()); BigInteger total_budget = new BigInteger(params.get("total_budget").asString()); @@ -460,16 +428,14 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data){ proposalAttributes.sponsor_address = sponsor_address; proposalAttributes.status = ACTIVE; depositProposalFund(proposalAttributes, _value); - } - else if (jsonObject.get("method").asString().equals("budget_adjustment")){ + } else if (jsonObject.get("method").asString().equals("budget_adjustment")) { String ipfs_key = params.get("_ipfs_key").asString(); BigInteger added_budget = new BigInteger(params.get("_added_budget").asString()); BigInteger added_sponsor_reward = new BigInteger(params.get("_added_sponsor_reward").asString()); int added_installment_count = Integer.parseInt(params.get("_added_installment_count").asString()); update_proposal_fund(ipfs_key, added_budget, added_sponsor_reward, added_installment_count); - } - else{ + } else { Context.revert(TAG + jsonObject.get("method").asString() + " Not a valid method."); } @@ -489,24 +455,31 @@ public void callScore(BigInteger amount, Address address, String method, Object. } @EventLog(indexed = 1) - public void FundReturned(Address _sponsor_address, String note){} + public void FundReturned(Address _sponsor_address, String note) { + } @EventLog(indexed = 1) - public void ProposalFundTransferred(String _ipfs_key, String note){} + public void ProposalFundTransferred(String _ipfs_key, String note) { + } @EventLog(indexed = 1) - public void ProposalDisqualified(String _ipfs_key, String note){} + public void ProposalDisqualified(String _ipfs_key, String note) { + } @EventLog(indexed = 1) - public void FundReceived(Address _sponsor_address, String note){} + public void FundReceived(Address _sponsor_address, String note) { + } @EventLog(indexed = 1) - public void ProposalFundDeposited(String _ipfs_key, String note){} + public void ProposalFundDeposited(String _ipfs_key, String note) { + } @EventLog(indexed = 1) - public void ProposalFundSent(Address _receiver_address, String note){} + public void ProposalFundSent(Address _receiver_address, String note) { + } @EventLog(indexed = 1) - public void ProposalFundWithdrawn(Address _receiver_address, String note){} + public void ProposalFundWithdrawn(Address _receiver_address, String note) { + } } From 3f189bfcc4ef6ccba5eee6de8059bd3abd9ccfa3 Mon Sep 17 00:00:00 2001 From: ibriz Date: Tue, 26 Apr 2022 12:33:21 +0545 Subject: [PATCH 018/112] made jsonobject to send data --- .../cps/score/cpstreasury/CPSTreasury.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index cc2e5968..c2fe47bb 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -370,24 +370,23 @@ public void disqualify_project(String _ipfs_key) { BigInteger remainingReward = sponsorReward.subtract(sponsorWithdrawAmount); BigInteger totalReturnAmount = remainingBudget.add(remainingReward); - try{ - if (flag.equals(consts.ICX)){ - callScore(totalReturnAmount, cpfTreasuryScore.get(), "disqualify_proposal_fund", _ipfs_key); - } - else if(flag.equals(consts.bnUSD)){ - String _data = "" + "{\"method\":\"disqualify_project\",\"params\":{\"ipfs_key\":" + "\"" + _ipfs_key + "\"" + "}}"; - callScore(balancedDollar.get(), "transfer", cpfTreasuryScore.get(), totalReturnAmount, _data.getBytes()); - } - else{ - Context.revert(TAG + ": Not supported token."); - } - ProposalDisqualified(_ipfs_key, _ipfs_key + ", Proposal disqualified"); - } - catch (Exception e){ - Context.revert(TAG + ": Network problem. Sending proposal funds to CPF after project disqualification."); + if (flag.equals(consts.ICX)) { + callScore(totalReturnAmount, cpfTreasuryScore.get(), "disqualify_proposal_fund", _ipfs_key); + } else if (flag.equals(consts.bnUSD)) { + JsonObject disqualifyProjectParams = new JsonObject(); + disqualifyProjectParams.add("method", "disqualify_project"); + JsonObject params = new JsonObject(); + params.add("ipfs_key", _ipfs_key); + disqualifyProjectParams.add("params", params); + + callScore(balancedDollar.get(), "transfer", cpfTreasuryScore.get(), totalReturnAmount, disqualifyProjectParams.toString().getBytes()); + } else { + Context.revert(TAG + ": Not supported token."); } + ProposalDisqualified(_ipfs_key, _ipfs_key + ", Proposal disqualified"); } + @External public void claim_reward() { BigInteger availableAmountICX = installmentFundRecord.at(Context.getCaller().toString()).get(consts.ICX); From b4e6811280574a57f1d357241b2ac098f5472097 Mon Sep 17 00:00:00 2001 From: ibriz Date: Tue, 26 Apr 2022 12:33:30 +0545 Subject: [PATCH 019/112] new big integer from radix 16 string --- .../icon/cps/score/cpstreasury/CPSTreasury.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index c2fe47bb..4e134619 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -411,9 +411,9 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { JsonObject params = jsonObject.get("params").asObject(); if (jsonObject.get("method").asString().equals("deposit_proposal_fund")) { String ipfs_hash = params.get("ipfs_hash").asString(); - int project_duration = Integer.parseInt(params.get("project_duration").asString()); - BigInteger total_budget = new BigInteger(params.get("total_budget").asString()); - BigInteger sponsor_reward = new BigInteger(params.get("sponsor_reward").asString()); + int project_duration = params.get("project_duration").asInt(); + BigInteger total_budget = new BigInteger(params.get("total_budget").asString(), 16); + BigInteger sponsor_reward = new BigInteger(params.get("sponsor_reward").asString(), 16); String token = params.get("token").asString(); String contributor_address = params.get("contributor_address").asString(); String sponsor_address = params.get("sponsor_address").asString(); @@ -429,9 +429,9 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { depositProposalFund(proposalAttributes, _value); } else if (jsonObject.get("method").asString().equals("budget_adjustment")) { String ipfs_key = params.get("_ipfs_key").asString(); - BigInteger added_budget = new BigInteger(params.get("_added_budget").asString()); - BigInteger added_sponsor_reward = new BigInteger(params.get("_added_sponsor_reward").asString()); - int added_installment_count = Integer.parseInt(params.get("_added_installment_count").asString()); + BigInteger added_budget = new BigInteger(params.get("_added_budget").asString(), 16); + BigInteger added_sponsor_reward = new BigInteger(params.get("_added_sponsor_reward").asString(), 16); + int added_installment_count = params.get("_added_installment_count").asInt(); update_proposal_fund(ipfs_key, added_budget, added_sponsor_reward, added_installment_count); } else { From 9e7b320a4384b1f861dffc3c2e104eebca94072b Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Tue, 26 Apr 2022 12:56:10 +0545 Subject: [PATCH 020/112] linter fixes unit tests --- .../score/cpstreasury/CPSTreasuryTest.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index 5e1095d2..36144a72 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -1,4 +1,5 @@ package community.icon.cps.score.cpstreasury; + import com.iconloop.score.test.Account; import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; @@ -20,7 +21,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; -public class CPSTreasuryTest extends TestBase{ +public class CPSTreasuryTest extends TestBase { private static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); private static final Address treasury_score = new Address(new byte[Address.LENGTH]); private static final Address score_address = Address.fromString("cx0000000000000000000000000000000000000000"); @@ -58,7 +59,7 @@ public void setup() throws Exception { } @Test - void name(){ + void name() { assertEquals(tokenScore.call("name"), name); } @@ -77,40 +78,40 @@ void fallbackExceptions(Account address) { } @Test - void fallback(){ + void fallback() { Executable fallback = () -> fallbackExceptions(owner); expectErrorMessage(fallback, "Reverted(0):" + " " + TAG + ": ICX can only be send by CPF Treasury Score"); } @Test - void setCpsScore(){ + void setCpsScore() { doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); } @Test - void setCPFTreasuryScore(){ + void setCPFTreasuryScore() { doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpfTreasuryScore", score_address); } @Test - void setBnUSDScore(){ + void setBnUSDScore() { doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setBnUSDScore", score_address); } - void setCpsScoreExceptions(Boolean isAdmin, Address score_address){ + void setCpsScoreExceptions(Boolean isAdmin, Address score_address) { doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); } - void setCpfTreasuryScoreExceptions(Boolean isAdmin, Address score_address){ + void setCpfTreasuryScoreExceptions(Boolean isAdmin, Address score_address) { doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpfTreasuryScore", score_address); } - void setBnUSDScoreExceptions(Boolean isAdmin, Address score_address){ + void setBnUSDScoreExceptions(Boolean isAdmin, Address score_address) { doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setBnUSDScore", score_address); } @@ -134,19 +135,19 @@ void setBnUSDScoreNotAdmin() { } @Test - void setCPSScoreNotContract(){ + void setCPSScoreNotContract() { Executable setCpsScoreNotAdmin = () -> setCpsScoreExceptions(true, testing_account.getAddress()); expectErrorMessage(setCpsScoreNotAdmin, TAG + "Target " + testing_account.getAddress() + " is not a score."); } @Test - void setCPFTreasuryScoreNotContract(){ + void setCPFTreasuryScoreNotContract() { Executable setCpfTreasuryScoreNotContract = () -> setCpfTreasuryScoreExceptions(true, testing_account.getAddress()); expectErrorMessage(setCpfTreasuryScoreNotContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); } @Test - void setBnUSDScoreNotContract(){ + void setBnUSDScoreNotContract() { Executable setBnUSDScoreContract = () -> setBnUSDScoreExceptions(true, testing_account.getAddress()); expectErrorMessage(setBnUSDScoreContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); } From cdfe8f961399fc74d97dc5358ff44953c0d9a5f7 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 10:24:42 +0545 Subject: [PATCH 021/112] added new returning variables in get method --- .../community/icon/cps/score/cpstreasury/db/ProposalData.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java index f8525d26..87dd82dd 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java @@ -66,7 +66,8 @@ public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ Map.entry(consts.SPONSOR_WITHDRAW_AMOUNT, sponsorWithdrawAmount.at(prefix).getOrDefault(BigInteger.ZERO)), Map.entry(consts.REMAINING_AMOUNT, remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO)), Map.entry(consts.SPONSOR_REMAINING_AMOUNT, sponsorRemainingAmount.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(consts.TOKEN, token.at(prefix).getOrDefault("")) + Map.entry(consts.TOKEN, token.at(prefix).getOrDefault("")), + Map.entry(consts.STATUS, status.at(prefix).getOrDefault("")) ); } From 3501e5aadab0e85d66fc109fbcb3213be81a2574 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 10:24:53 +0545 Subject: [PATCH 022/112] added new tests --- .../score/cpstreasury/CPSTreasuryTest.java | 141 +++++++++++++++++- 1 file changed, 140 insertions(+), 1 deletion(-) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index 36144a72..c5a6483c 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -151,4 +151,143 @@ void setBnUSDScoreNotContract() { Executable setBnUSDScoreContract = () -> setBnUSDScoreExceptions(true, testing_account.getAddress()); expectErrorMessage(setBnUSDScoreContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); } -} + + @Test + void depositProposalFund() { + depositProposalFundMethod(); + @SuppressWarnings("unchecked") + Map proposalDataDetails = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); + @SuppressWarnings("unchecked") + List> proposalDetails = (List>) proposalDataDetails.get("data"); + Map expectedData = Map.of( + consts.IPFS_HASH, "Proposal 1", + consts.TOKEN, "bnUSD", + consts.TOTAL_BUDGET, BigInteger.valueOf(100).multiply(MULTIPLIER).toString(), + consts.TOTAL_INSTALLMENT_PAID, BigInteger.ZERO.toString(), + consts.TOTAL_INSTALLMENT_COUNT, "2", + consts.TOTAL_TIMES_INSTALLMENT_PAID, "0", + consts.INSTALLMENT_AMOUNT, BigInteger.valueOf(50).multiply(MULTIPLIER).toString()); + assertEquals(proposalDetails.get(0), expectedData); + } + + private void depositProposalFundMethod() { + JsonObject depositProposal = new JsonObject(); + depositProposal.add("method", "deposit_proposal_fund"); + JsonObject params = new JsonObject(); + params.add("ipfs_hash", "Proposal 1"); + params.add("project_duration", 2); + params.add("sponsor_address", testing_account.getAddress().toString()); + params.add("contributor_address", testing_account2.getAddress().toString()); + params.add("total_budget", BigInteger.valueOf(100).multiply(MULTIPLIER).toString(16)); + params.add("sponsor_reward", BigInteger.valueOf(2).multiply(MULTIPLIER).toString(16)); + params.add("token", "bnUSD"); + depositProposal.add("params", params); + setCPFTreasuryScoreMethod(); + tokenScore.invoke(owner, "tokenFallback", cpfTreasury, BigInteger.valueOf(102).multiply(MULTIPLIER), depositProposal.toString().getBytes()); + } + + @Test + void updateProposalFund() { + depositProposalFundMethod(); + JsonObject budgetAdjustmentData = new JsonObject(); + budgetAdjustmentData.add("method", "budget_adjustment"); + JsonObject params = new JsonObject(); + params.add("_ipfs_key", "Proposal 1"); + params.add("_added_budget", BigInteger.valueOf(100).multiply(MULTIPLIER).toString(16)); + params.add("_added_sponsor_reward", BigInteger.valueOf(2).multiply(MULTIPLIER).toString(16)); + params.add("_added_installment_count", 1); + budgetAdjustmentData.add("params", params); + + tokenScore.invoke(owner, "tokenFallback", cpfTreasury, BigInteger.valueOf(102).multiply(MULTIPLIER), budgetAdjustmentData.toString().getBytes()); + + @SuppressWarnings("unchecked") + Map proposalDataDetails = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); + @SuppressWarnings("unchecked") + List> proposalDetails = (List>) proposalDataDetails.get("data"); + Map expectedData = Map.of( + consts.IPFS_HASH, "Proposal 1", + consts.TOKEN, "bnUSD", + consts.TOTAL_BUDGET, BigInteger.valueOf(200).multiply(MULTIPLIER).toString(), + consts.TOTAL_INSTALLMENT_PAID, BigInteger.ZERO.toString(), + consts.TOTAL_INSTALLMENT_COUNT, "3", + consts.TOTAL_TIMES_INSTALLMENT_PAID, "0", + consts.INSTALLMENT_AMOUNT, "66666666666666666666"); + assertEquals(proposalDetails.get(0), expectedData); + } + + @Test + void sendInstallmentToContributor() { + depositProposalFundMethod(); + setCpsScoreMethod(); + try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { + theMock.when(() -> Context.getCaller()).thenReturn(score_address); + tokenScore.invoke(owner, "send_installment_to_contributor", "Proposal 1"); + } + @SuppressWarnings("unchecked") + Map proposalDataDetails = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); + assertEquals(proposalDataDetails.get("withdraw_amount_bnUSD"), BigInteger.valueOf(50).multiply(MULTIPLIER)); + + try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { + theMock.when(() -> Context.getCaller()).thenReturn(score_address); + tokenScore.invoke(owner, "send_installment_to_contributor", "Proposal 1"); + } + @SuppressWarnings("unchecked") + Map proposalDataDetails2 = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); + assertEquals(proposalDataDetails2.get("withdraw_amount_bnUSD"), BigInteger.valueOf(100).multiply(MULTIPLIER)); + } + + @Test + void sendRewardToSponsor() { + depositProposalFundMethod(); + setCpsScoreMethod(); + sendRewardToSponsorMethod(); + @SuppressWarnings("unchecked") + Map proposalDataDetails = (Map) tokenScore.call("get_sponsor_projected_fund", testing_account.getAddress()); + assertEquals(proposalDataDetails.get("withdraw_amount_bnUSD"), BigInteger.valueOf(1).multiply(MULTIPLIER)); + + try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { + theMock.when(() -> Context.getCaller()).thenReturn(score_address); + tokenScore.invoke(owner, "send_reward_to_sponsor", "Proposal 1"); + } + @SuppressWarnings("unchecked") + Map proposalDataDetails2 = (Map) tokenScore.call("get_sponsor_projected_fund", testing_account.getAddress()); + assertEquals(proposalDataDetails2.get("withdraw_amount_bnUSD"), BigInteger.valueOf(2).multiply(MULTIPLIER)); + } + + private void sendRewardToSponsorMethod() { + try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { + theMock.when(() -> Context.getCaller()).thenReturn(score_address); + tokenScore.invoke(owner, "send_reward_to_sponsor", "Proposal 1"); + } + } + + @Test + void disqualifyProject(){ + depositProposalFundMethod(); + setCPFTreasuryScoreMethod(); + setCpsScoreMethod(); + setBnUSDScoreMethod(); + try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { + theMock.when(() -> Context.getCaller()).thenReturn(score_address); + tokenScore.invoke(owner, "disqualify_project", "Proposal 1"); + JsonObject disqualifyProjectParams = new JsonObject(); + disqualifyProjectParams.add("method", "disqualify_project"); + JsonObject params = new JsonObject(); + params.add("ipfs_key", "Proposal 1"); + disqualifyProjectParams.add("params", params); + theMock.verify(() -> Context.call(bnUSDScore, "transfer", cpfTreasury, BigInteger.valueOf(102).multiply(MULTIPLIER), disqualifyProjectParams.toString().getBytes()), times(1)); + } + } + + @Test + void claimReward(){ + depositProposalFundMethod(); + sendRewardToSponsorMethod(); + setBnUSDScoreMethod(); + try(MockedStatic theMock = Mockito.mockStatic(Context.class)) { + theMock.when(() -> Context.getCaller()).thenReturn(testing_account.getAddress()); + tokenScore.invoke(testing_account, "claim_reward"); + theMock.verify(() -> Context.call(bnUSDScore, "transfer", testing_account.getAddress(), BigInteger.valueOf(1).multiply(MULTIPLIER)), times(1)); + } + } +} \ No newline at end of file From c83f9085d808c6fcd0edacfed76cf44787e91807 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 10:25:01 +0545 Subject: [PATCH 023/112] corrected totalPaidCount calculation --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 4e134619..b0aaf054 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -168,7 +168,7 @@ public Address getBnUSDScore() { if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); - int totalPaidCount = (int) proposal_details.get(consts.INSTALLMENT_COUNT); + int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.INSTALLMENT_COUNT); if (totalPaidCount < totalInstallment) { String flag = (String) proposal_details.get(consts.TOKEN); BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); From 02f10e4d440c777a0148d1dbccf0feae855e77f9 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 10:25:09 +0545 Subject: [PATCH 024/112] getOrDefault instead of get --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index b0aaf054..e9d3a2a4 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -315,7 +315,7 @@ public void send_installment_to_contributor(String _ipfs_key) { setRemainingAmount(prefix, remainingAmount.subtract(installmentAmount)); setWithdrawAmount(prefix, withdrawAmount.add(installmentAmount)); installmentFundRecord.at(contributorAddress.toString()).set(flag, - installmentFundRecord.at(contributorAddress.toString()).get(flag).add(installmentAmount)); + installmentFundRecord.at(contributorAddress.toString()).getOrDefault(flag, BigInteger.ZERO).add(installmentAmount)); ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); if (newInstallmentCount == 0) { @@ -347,7 +347,7 @@ public void send_reward_to_sponsor(String _ipfs_key) { setSponsorRewardCount(prefix, newSponsorRewardCount); setSponsorWithdrawAmount(prefix, sponsorWithdrawAmount.add(installmentAmount)); setSponsorRemainingAmount(prefix, sponsorRemainingAmount.subtract(installmentAmount)); - installmentFundRecord.at(sponsorAddress.toString()).set(flag, installmentFundRecord.at(sponsorAddress.toString()).get(flag).add(installmentAmount)); + installmentFundRecord.at(sponsorAddress.toString()).set(flag, installmentFundRecord.at(sponsorAddress.toString()).getOrDefault(flag, BigInteger.ZERO).add(installmentAmount)); ProposalFundSent(sponsorAddress, "New installment " + installmentAmount + " " + flag + " sent to sponsor address."); } @@ -389,8 +389,8 @@ public void disqualify_project(String _ipfs_key) { @External public void claim_reward() { - BigInteger availableAmountICX = installmentFundRecord.at(Context.getCaller().toString()).get(consts.ICX); - BigInteger availableAmountbnUSD = installmentFundRecord.at(Context.getCaller().toString()).get(consts.bnUSD); + BigInteger availableAmountICX = installmentFundRecord.at(Context.getCaller().toString()).getOrDefault(consts.ICX, BigInteger.ZERO); + BigInteger availableAmountbnUSD = installmentFundRecord.at(Context.getCaller().toString()).getOrDefault(consts.bnUSD, BigInteger.ZERO); if (availableAmountICX.compareTo(BigInteger.ZERO) > 0) { installmentFundRecord.at(Context.getCaller().toString()).set(consts.ICX, BigInteger.ZERO); Context.transfer(Context.getCaller(), availableAmountICX); From df28378389abb367f925a675edceb9d3d0f40259 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 10:25:21 +0545 Subject: [PATCH 025/112] imports --- .../icon/cps/score/cpstreasury/CPSTreasuryTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index c5a6483c..c322b83c 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -1,20 +1,26 @@ package community.icon.cps.score.cpstreasury; +import com.eclipsesource.json.JsonObject; import com.iconloop.score.test.Account; import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; import com.iconloop.score.test.TestBase; +import community.icon.cps.score.cpstreasury.utils.consts; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; +import org.mockito.MockedStatic; import org.mockito.Mockito; import score.Address; +import score.Context; import score.DictDB; import score.VarDB; import java.math.BigInteger; import java.security.SecureRandom; +import java.util.List; +import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; From 510f67c7bcec74d7c5ed41fd0cd7a8a9903cba7b Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 10:25:34 +0545 Subject: [PATCH 026/112] new contract variables in testing --- .../community/icon/cps/score/cpstreasury/CPSTreasuryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index c322b83c..8c661b55 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -31,7 +31,7 @@ public class CPSTreasuryTest extends TestBase { private static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); private static final Address treasury_score = new Address(new byte[Address.LENGTH]); private static final Address score_address = Address.fromString("cx0000000000000000000000000000000000000000"); - private static final Address sicxScore = Address.fromString("cx0000000000000000000000000000000000000001"); + private static final Address cpfTreasury = Address.fromString("cx0000000000000000000000000000000000000001"); private static final Address bnUSDScore = Address.fromString("cx0000000000000000000000000000000000000002"); private static final Address dexScore = Address.fromString("cx0000000000000000000000000000000000000003"); private static final Address cpsTreasuryScore = Address.fromString("cx0000000000000000000000000000000000000004"); From e7ef42696611d298b05ab331525cdc97bd8afbba Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 10:25:42 +0545 Subject: [PATCH 027/112] proposal prefix as key instead of ipfs_hash --- .../icon/cps/score/cpstreasury/CPSTreasury.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index e9d3a2a4..94fd3f73 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -114,7 +114,8 @@ private void addRecord(ProposalData.ProposalAttributes _proposal) { String ipfs_hash = _proposal.ipfs_hash; Context.require(!proposalExists(ipfs_hash), TAG + ": Already have this project"); proposalsKeys.add(ipfs_hash); - proposalData.addDataToProposalDB(_proposal, ipfs_hash); + String proposalPrefix = proposalPrefix(ipfs_hash); + proposalData.addDataToProposalDB(_proposal, proposalPrefix); proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); } @@ -164,9 +165,11 @@ public Address getBnUSDScore() { List> projectDetails = new ArrayList<>(); for (int i = 0; i < proposalsKeys.size(); i++) { String _ipfs_key = proposalsKeys.get(i); - Map proposal_details = proposalData.getDataFromProposalDB(_ipfs_key); - if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { - if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())) { + String proposalPrefix = proposalPrefix(_ipfs_key); + Map proposal_details = proposalData.getDataFromProposalDB(proposalPrefix); + if (!proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { + String contributorAddress = proposal_details.get(consts.CONTRIBUTOR_ADDRESS).toString(); + if (contributorAddress.equals(_wallet_address.toString())) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.INSTALLMENT_COUNT); if (totalPaidCount < totalInstallment) { @@ -212,7 +215,8 @@ public Address getBnUSDScore() { List> projectDetails = new ArrayList<>(); for (int i = 0; i < proposalsKeys.size(); i++) { String _ipfs_key = proposalsKeys.get(i); - Map proposal_details = proposalData.getDataFromProposalDB(_ipfs_key); + String proposalPrefix = proposalPrefix(_ipfs_key); + Map proposal_details = proposalData.getDataFromProposalDB(proposalPrefix); if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); From 04b2a76099fcf7640d10ac99e41ebd4703e607db Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 10:25:49 +0545 Subject: [PATCH 028/112] seperated setters test into methods --- .../cps/score/cpstreasury/CPSTreasuryTest.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index 8c661b55..05c39dd4 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -91,20 +91,34 @@ void fallback() { @Test void setCpsScore() { + setCpsScoreMethod(); + } + + private void setCpsScoreMethod() { doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); } @Test void setCPFTreasuryScore() { + setCPFTreasuryScoreMethod(); + } + + private void setCPFTreasuryScoreMethod() { doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); - tokenScore.invoke(owner, "setCpfTreasuryScore", score_address); + tokenScore.invoke(owner, "setCpfTreasuryScore", cpfTreasury); + assertEquals(cpfTreasury, tokenScore.call("getCpfTreasuryScore")); } @Test void setBnUSDScore() { + setBnUSDScoreMethod(); + } + + private void setBnUSDScoreMethod() { doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); - tokenScore.invoke(owner, "setBnUSDScore", score_address); + tokenScore.invoke(owner, "setBnUSDScore", bnUSDScore); + assertEquals(bnUSDScore, tokenScore.call("getBnUSDScore")); } void setCpsScoreExceptions(Boolean isAdmin, Address score_address) { From ff62755e9bc8f1d75f8d9b6d9093a5180a571326 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 11:32:57 +0545 Subject: [PATCH 029/112] corrected totalPaidCount calculation --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 94fd3f73..bc0a7e41 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -220,7 +220,7 @@ public Address getBnUSDScore() { if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); - int totalPaidCount = (int) proposal_details.get(consts.INSTALLMENT_COUNT); + int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.SPONSOR_REWARD_COUNT); if (totalPaidCount < totalInstallment) { String flag = (String) proposal_details.get(consts.TOKEN); BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); From 3775607447e3434f95a790dc4afe9b1cd77a8b79 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 11:33:04 +0545 Subject: [PATCH 030/112] fixed compare logic --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index bc0a7e41..0a4b690a 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -217,8 +217,8 @@ public Address getBnUSDScore() { String _ipfs_key = proposalsKeys.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); Map proposal_details = proposalData.getDataFromProposalDB(proposalPrefix); - if (proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { - if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address.toString())) { + if (!proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { + if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address)) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.SPONSOR_REWARD_COUNT); if (totalPaidCount < totalInstallment) { From 6c90ed1fa49284bfee3c293240b4f39e3c89a8e5 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 11:33:12 +0545 Subject: [PATCH 031/112] fixed sponsor bond calculation --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 0a4b690a..1bb5d22e 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -225,7 +225,7 @@ public Address getBnUSDScore() { String flag = (String) proposal_details.get(consts.TOKEN); BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); - BigInteger depositedSponsorBond = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); + BigInteger depositedSponsorBond = ((BigInteger) proposal_details.get(consts.TOTAL_BUDGET)).divide(BigInteger.TEN); Map project_details = Map.of( consts.IPFS_HASH, _ipfs_key, From fa1fef859b40295857d4a17195663d1316263b31 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 27 Apr 2022 11:33:19 +0545 Subject: [PATCH 032/112] removed redundant `toString` --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 1bb5d22e..0bfa84d2 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -168,8 +168,7 @@ public Address getBnUSDScore() { String proposalPrefix = proposalPrefix(_ipfs_key); Map proposal_details = proposalData.getDataFromProposalDB(proposalPrefix); if (!proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { - String contributorAddress = proposal_details.get(consts.CONTRIBUTOR_ADDRESS).toString(); - if (contributorAddress.equals(_wallet_address.toString())) { + if (proposal_details.get(consts.CONTRIBUTOR_ADDRESS).equals(_wallet_address)) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.INSTALLMENT_COUNT); if (totalPaidCount < totalInstallment) { From 91d7ad90e2533ffeb58275747542f0e788a196af Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 09:56:08 +0545 Subject: [PATCH 033/112] accessed the inherited method without the object --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 0bfa84d2..4f94a2c3 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -109,13 +109,12 @@ private void validateCpfTreasuryScore() { TAG + ": Only CPF Treasury score " + cpfTreasuryScore.get() + " can send fund using this method."); } - private void addRecord(ProposalData.ProposalAttributes _proposal) { - ProposalData proposalData = new ProposalData(); + private void addRecord(ProposalAttributes _proposal) { String ipfs_hash = _proposal.ipfs_hash; Context.require(!proposalExists(ipfs_hash), TAG + ": Already have this project"); proposalsKeys.add(ipfs_hash); String proposalPrefix = proposalPrefix(ipfs_hash); - proposalData.addDataToProposalDB(_proposal, proposalPrefix); + addDataToProposalDB(_proposal, proposalPrefix); proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); } @@ -159,7 +158,6 @@ public Address getBnUSDScore() { @External(readonly = true) public Map get_contributor_projected_fund(Address _wallet_address) { - ProposalData proposalData = new ProposalData(); BigInteger totalAmountToBePaidICX = BigInteger.ZERO; BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; List> projectDetails = new ArrayList<>(); From 6f32c26f6a9d170e62ced29b5e8e2c6ffdee3adf Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 09:56:19 +0545 Subject: [PATCH 034/112] added installment fund calculation --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 1 + 1 file changed, 1 insertion(+) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 4f94a2c3..1637f2b2 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -193,6 +193,7 @@ public Address getBnUSDScore() { } } } + DictDB installmentRecord = installmentFundRecord.at(_wallet_address.toString()); return Map.of( "data", projectDetails, "project_count", projectDetails.size(), From 245b61a738d7f8bc09490271afe8fc0daf485bf0 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 09:56:26 +0545 Subject: [PATCH 035/112] added new tests --- .../score/cpstreasury/CPSTreasuryTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index 05c39dd4..7a24fda2 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -206,6 +206,21 @@ private void depositProposalFundMethod() { tokenScore.invoke(owner, "tokenFallback", cpfTreasury, BigInteger.valueOf(102).multiply(MULTIPLIER), depositProposal.toString().getBytes()); } + void depositProposalFundExceptions(){ + try{ + depositProposalFundMethod(); + } + catch (Exception e){ + throw e; + } + } + @Test + void depositProposalFundProposalAlreadyExists(){ + depositProposalFundMethod(); + Executable depositProposalFundProposalAlreadyExists = () -> depositProposalFundExceptions(); + expectErrorMessage(depositProposalFundProposalAlreadyExists, "CPS_TREASURY: Already have this project"); + } + @Test void updateProposalFund() { depositProposalFundMethod(); @@ -235,6 +250,31 @@ void updateProposalFund() { assertEquals(proposalDetails.get(0), expectedData); } + void updateProposalFundProposalException(){ + try { + setCPFTreasuryScoreMethod(); + JsonObject budgetAdjustmentData = new JsonObject(); + budgetAdjustmentData.add("method", "budget_adjustment"); + JsonObject params = new JsonObject(); + params.add("_ipfs_key", "Proposal 1"); + params.add("_added_budget", BigInteger.valueOf(100).multiply(MULTIPLIER).toString(16)); + params.add("_added_sponsor_reward", BigInteger.valueOf(2).multiply(MULTIPLIER).toString(16)); + params.add("_added_installment_count", 1); + budgetAdjustmentData.add("params", params); + + tokenScore.invoke(owner, "tokenFallback", cpfTreasury, BigInteger.valueOf(102).multiply(MULTIPLIER), budgetAdjustmentData.toString().getBytes()); + } + catch (Exception e){ + throw e; + } + } + + @Test + void updateProposalFundProposalDoesnotExist(){ + Executable updateProposalFundProposalDoesnotExist = () -> updateProposalFundProposalException(); + expectErrorMessage(updateProposalFundProposalDoesnotExist, "CPS_TREASURY: Invalid IPFS hash."); + } + @Test void sendInstallmentToContributor() { depositProposalFundMethod(); From d731c2415edba30bd8c77f5be99381280e838cba Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 09:56:33 +0545 Subject: [PATCH 036/112] changed the variable type --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 1637f2b2..043cfcc9 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -160,7 +160,7 @@ public Address getBnUSDScore() { public Map get_contributor_projected_fund(Address _wallet_address) { BigInteger totalAmountToBePaidICX = BigInteger.ZERO; BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; - List> projectDetails = new ArrayList<>(); + List> projectDetails = new ArrayList<>(); for (int i = 0; i < proposalsKeys.size(); i++) { String _ipfs_key = proposalsKeys.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); @@ -174,7 +174,7 @@ public Address getBnUSDScore() { BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); - Map project_details = Map.of( + Map project_details = Map.of( consts.IPFS_HASH, _ipfs_key, consts.TOKEN, flag, consts.TOTAL_BUDGET, totalBudget.toString(), From a3f6afff83f2f35d379267a528d7434bc2fc8ddb Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 09:56:42 +0545 Subject: [PATCH 037/112] Linter fix --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 3 ++- .../community/icon/cps/score/cpstreasury/CPSTreasuryTest.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 043cfcc9..d430b8af 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -16,7 +16,7 @@ import community.icon.cps.score.cpstreasury.utils.consts; public class CPSTreasury extends ProposalData { - private static final String TAG = "CPS_Treasury"; + private static final String TAG = "CPS_TREASURY"; private static final String PROPOSAL_DB_PREFIX = "proposal"; private static final String ID = "id"; @@ -169,6 +169,7 @@ public Address getBnUSDScore() { if (proposal_details.get(consts.CONTRIBUTOR_ADDRESS).equals(_wallet_address)) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.INSTALLMENT_COUNT); + if (totalPaidCount < totalInstallment) { String flag = (String) proposal_details.get(consts.TOKEN); BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index 7a24fda2..e852059b 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -97,6 +97,7 @@ void setCpsScore() { private void setCpsScoreMethod() { doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); + assertEquals(score_address, tokenScore.call("getCpsScore")); } @Test From bd604a108b8226a28ccf84430b4eafe155bee2c0 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 09:56:49 +0545 Subject: [PATCH 038/112] removed redundant `toString` --- .../icon/cps/score/cpstreasury/CPSTreasury.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index d430b8af..f2d85765 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -178,11 +178,11 @@ public Address getBnUSDScore() { Map project_details = Map.of( consts.IPFS_HASH, _ipfs_key, consts.TOKEN, flag, - consts.TOTAL_BUDGET, totalBudget.toString(), - consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount.toString(), - consts.TOTAL_INSTALLMENT_COUNT, String.valueOf(totalInstallment), - consts.TOTAL_TIMES_INSTALLMENT_PAID, String.valueOf(totalPaidCount), - consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)).toString()); + consts.TOTAL_BUDGET, totalBudget, + consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount, + consts.TOTAL_INSTALLMENT_COUNT, totalInstallment, + consts.TOTAL_TIMES_INSTALLMENT_PAID, totalPaidCount, + consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment))); projectDetails.add(project_details); if (flag.equals(consts.ICX)) { @@ -199,8 +199,8 @@ public Address getBnUSDScore() { "data", projectDetails, "project_count", projectDetails.size(), "total_amount", Map.of("ICX", totalAmountToBePaidICX, "bnUSD", totalAmountToBePaidbnUSD), - "withdraw_amount_icx", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.ICX, BigInteger.ZERO), - "withdraw_amount_bnUSD", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.bnUSD, BigInteger.ZERO)); + "withdraw_amount_icx", installmentRecord.getOrDefault(consts.ICX, BigInteger.ZERO), + "withdraw_amount_bnUSD", installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO)); } From b0164658c325a47674e68addde21fca847e4d9b9 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 09:56:55 +0545 Subject: [PATCH 039/112] TODO --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index f2d85765..7563ffdf 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -129,7 +129,7 @@ public void setCpsScore(Address _score) { cpsScore.set(_score); } - @External(readonly = true) + @External(readonly = true) //Todo java convention in get methods?? public Address getCpsScore() { return cpsScore.get(); } @@ -164,7 +164,8 @@ public Address getBnUSDScore() { for (int i = 0; i < proposalsKeys.size(); i++) { String _ipfs_key = proposalsKeys.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); - Map proposal_details = proposalData.getDataFromProposalDB(proposalPrefix); + // todo: getting entire proposal details or getting individual values? + Map proposal_details = getDataFromProposalDB(proposalPrefix); if (!proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { if (proposal_details.get(consts.CONTRIBUTOR_ADDRESS).equals(_wallet_address)) { int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); From a6a23361a8f6f8537837e45103d5805b665e7495 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 10:12:20 +0545 Subject: [PATCH 040/112] Linter fix --- .../community/icon/cps/score/cpstreasury/CPSTreasuryTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index e852059b..6403736c 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -36,8 +36,8 @@ public class CPSTreasuryTest extends TestBase { private static final Address dexScore = Address.fromString("cx0000000000000000000000000000000000000003"); private static final Address cpsTreasuryScore = Address.fromString("cx0000000000000000000000000000000000000004"); - private static final String name = "CPS_Treasury"; - public static final String TAG = "CPS_Treasury"; + private static final String name = "CPS_TREASURY"; + public static final String TAG = "CPS_TREASURY"; CPSTreasury cpsTreasury; private static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); From c9da7e5b55263e45abfe746a2b379b6f87c15304 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 10:12:29 +0545 Subject: [PATCH 041/112] updated test after the changes --- .../score/cpstreasury/CPSTreasuryTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index 6403736c..a159db33 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -179,15 +179,15 @@ void depositProposalFund() { @SuppressWarnings("unchecked") Map proposalDataDetails = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); @SuppressWarnings("unchecked") - List> proposalDetails = (List>) proposalDataDetails.get("data"); - Map expectedData = Map.of( + List> proposalDetails = (List>) proposalDataDetails.get("data"); + Map expectedData = Map.of( consts.IPFS_HASH, "Proposal 1", consts.TOKEN, "bnUSD", - consts.TOTAL_BUDGET, BigInteger.valueOf(100).multiply(MULTIPLIER).toString(), - consts.TOTAL_INSTALLMENT_PAID, BigInteger.ZERO.toString(), - consts.TOTAL_INSTALLMENT_COUNT, "2", - consts.TOTAL_TIMES_INSTALLMENT_PAID, "0", - consts.INSTALLMENT_AMOUNT, BigInteger.valueOf(50).multiply(MULTIPLIER).toString()); + consts.TOTAL_BUDGET, BigInteger.valueOf(100).multiply(MULTIPLIER), + consts.TOTAL_INSTALLMENT_PAID, BigInteger.ZERO, + consts.TOTAL_INSTALLMENT_COUNT, 2, + consts.TOTAL_TIMES_INSTALLMENT_PAID, 0, + consts.INSTALLMENT_AMOUNT, BigInteger.valueOf(50).multiply(MULTIPLIER)); assertEquals(proposalDetails.get(0), expectedData); } @@ -239,15 +239,15 @@ void updateProposalFund() { @SuppressWarnings("unchecked") Map proposalDataDetails = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); @SuppressWarnings("unchecked") - List> proposalDetails = (List>) proposalDataDetails.get("data"); - Map expectedData = Map.of( + List> proposalDetails = (List>) proposalDataDetails.get("data"); + Map expectedData = Map.of( consts.IPFS_HASH, "Proposal 1", consts.TOKEN, "bnUSD", - consts.TOTAL_BUDGET, BigInteger.valueOf(200).multiply(MULTIPLIER).toString(), - consts.TOTAL_INSTALLMENT_PAID, BigInteger.ZERO.toString(), - consts.TOTAL_INSTALLMENT_COUNT, "3", - consts.TOTAL_TIMES_INSTALLMENT_PAID, "0", - consts.INSTALLMENT_AMOUNT, "66666666666666666666"); + consts.TOTAL_BUDGET, BigInteger.valueOf(200).multiply(MULTIPLIER), + consts.TOTAL_INSTALLMENT_PAID, BigInteger.ZERO, + consts.TOTAL_INSTALLMENT_COUNT, 3, + consts.TOTAL_TIMES_INSTALLMENT_PAID, 0, + consts.INSTALLMENT_AMOUNT, new BigInteger("66666666666666666666")); assertEquals(proposalDetails.get(0), expectedData); } From 268f0d6ff1f09504642f16d54d5a51de31aa072f Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 10:30:40 +0545 Subject: [PATCH 042/112] Linter fix --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 7563ffdf..e84c9134 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -89,8 +89,7 @@ private Boolean proposalExists(String _ipfs_key) { private void validateAdmins() { Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "is_admin", Context.getCaller()); - Context.require(isAdmin, - TAG + ": Only admins can call this method"); + Context.require(isAdmin, TAG + ": Only admins can call this method"); } @@ -100,8 +99,7 @@ private void validateAdminScore(Address _score) { } private void validateCpsScore() { - Context.require(Context.getCaller().equals(cpsScore.get()), - TAG + ": Only CPS score " + cpsScore.get() + " can send fund using this method."); + Context.require(Context.getCaller().equals(cpsScore.get()), TAG + ": Only CPS score " + cpsScore.get() + " can send fund using this method."); } private void validateCpfTreasuryScore() { @@ -441,10 +439,8 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { } else { Context.revert(TAG + jsonObject.get("method").asString() + " Not a valid method."); } - } - public T callScore(Class t, Address address, String method, Object... params) { return Context.call(t, address, method, params); } From 45fb14e6484037ddd2ffcf27efcad43b76d4d049 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 2 May 2022 10:30:47 +0545 Subject: [PATCH 043/112] removed unused methods --- .../icon/cps/score/cpstreasury/CPSTreasury.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index e84c9134..84ece152 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -102,11 +102,6 @@ private void validateCpsScore() { Context.require(Context.getCaller().equals(cpsScore.get()), TAG + ": Only CPS score " + cpsScore.get() + " can send fund using this method."); } - private void validateCpfTreasuryScore() { - Context.require(Context.getCaller().equals(cpfTreasuryScore.get()), - TAG + ": Only CPF Treasury score " + cpfTreasuryScore.get() + " can send fund using this method."); - } - private void addRecord(ProposalAttributes _proposal) { String ipfs_hash = _proposal.ipfs_hash; Context.require(!proposalExists(ipfs_hash), TAG + ": Already have this project"); @@ -453,22 +448,10 @@ public void callScore(BigInteger amount, Address address, String method, Object. Context.call(amount, address, method, params); } - @EventLog(indexed = 1) - public void FundReturned(Address _sponsor_address, String note) { - } - - @EventLog(indexed = 1) - public void ProposalFundTransferred(String _ipfs_key, String note) { - } - @EventLog(indexed = 1) public void ProposalDisqualified(String _ipfs_key, String note) { } - @EventLog(indexed = 1) - public void FundReceived(Address _sponsor_address, String note) { - } - @EventLog(indexed = 1) public void ProposalFundDeposited(String _ipfs_key, String note) { } From 07c65ef3d6a922551004e68490066f75fbd279a1 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Tue, 3 May 2022 13:18:09 +0545 Subject: [PATCH 044/112] removed redundant `toString` --- .../icon/cps/score/cpstreasury/CPSTreasury.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 84ece152..832207ed 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -223,12 +223,12 @@ public Address getBnUSDScore() { Map project_details = Map.of( consts.IPFS_HASH, _ipfs_key, consts.TOKEN, flag, - consts.TOTAL_BUDGET, totalBudget.toString(), - consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount.toString(), - consts.TOTAL_INSTALLMENT_COUNT, String.valueOf(totalInstallment), - consts.TOTAL_TIMES_INSTALLMENT_PAID, String.valueOf(totalPaidCount), - consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)).toString(), - consts.SPONSOR_BOND_AMOUNT, depositedSponsorBond.toString()); + consts.TOTAL_BUDGET, totalBudget, + consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount, + consts.TOTAL_INSTALLMENT_COUNT, totalInstallment, + consts.TOTAL_TIMES_INSTALLMENT_PAID, totalPaidCount, + consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)), + consts.SPONSOR_BOND_AMOUNT, depositedSponsorBond); projectDetails.add(project_details); if (flag.equals(consts.ICX)) { From 23d98e07f967082128d448d0a718f8b914f99357 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Tue, 3 May 2022 13:18:23 +0545 Subject: [PATCH 045/112] Linter fix --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 2 +- .../community/icon/cps/score/cpstreasury/db/ProposalData.java | 4 ++-- .../community/icon/cps/score/cpstreasury/utils/consts.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 832207ed..bf04783d 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -267,7 +267,7 @@ public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, Big String proposalPrefix = proposalPrefix(_ipfs_key); Map proposalDetails = proposalData.getDataFromProposalDB(proposalPrefix); BigInteger totalBudget = (BigInteger) proposalDetails.get(consts.TOTAL_BUDGET); - BigInteger sponsorReward = (BigInteger) proposalDetails.get(consts.SPONSORS_REWARDS); + BigInteger sponsorReward = (BigInteger) proposalDetails.get(consts.SPONSOR_REWARD); int totalDuration = (int) proposalDetails.get(consts.PROJECT_DURATION); BigInteger remainingAmount = (BigInteger) proposalDetails.get(consts.REMAINING_AMOUNT); BigInteger sponsorRemainingAmount = (BigInteger) proposalDetails.get(consts.SPONSOR_REMAINING_AMOUNT); diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java index 87dd82dd..f9ae7de4 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java @@ -19,7 +19,7 @@ public static class ProposalAttributes{ } private final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); private final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); - private final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSORS_REWARDS, BigInteger.class); + private final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSOR_REWARD, BigInteger.class); private final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); private final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); private final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); @@ -56,7 +56,7 @@ public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ return Map.ofEntries( Map.entry(consts.IPFS_HASH, ipfsHash.at(prefix).getOrDefault("")), Map.entry(consts.TOTAL_BUDGET, totalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(consts.SPONSORS_REWARDS, sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(consts.SPONSOR_REWARD, sponsorReward.at(prefix).getOrDefault(BigInteger.ZERO)), Map.entry(consts.PROJECT_DURATION, projectDuration.at(prefix).getOrDefault(0)), Map.entry(consts.SPONSOR_ADDRESS, sponsorAddress.at(prefix).get()), Map.entry(consts.CONTRIBUTOR_ADDRESS, contributorAddress.at(prefix).get()), diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java index adb5dfc2..16eeb4f5 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java @@ -117,7 +117,7 @@ public consts(){} public static final String ICX = "ICX"; public static final String bnUSD = "bnUSD"; - public static final String SPONSORS_REWARDS = "sponsor_reward"; + public static final String SPONSOR_REWARD = "sponsor_reward"; public static final String SPONSOR_ADDRESS = "sponsor_address"; public static final String CONTRIBUTOR_ADDRESS = "contributor_address"; public static final String WITHDRAW_AMOUNT = "withdraw_amount"; From bf0fd7d2b1fe71faaac224300a806423dcb9ada3 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Tue, 3 May 2022 13:18:31 +0545 Subject: [PATCH 046/112] fixed `total budget` calculation --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index bf04783d..89386a6b 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -216,7 +216,7 @@ public Address getBnUSDScore() { int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.SPONSOR_REWARD_COUNT); if (totalPaidCount < totalInstallment) { String flag = (String) proposal_details.get(consts.TOKEN); - BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); + BigInteger totalBudget = (BigInteger) proposal_details.get(consts.SPONSOR_REWARD); BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); BigInteger depositedSponsorBond = ((BigInteger) proposal_details.get(consts.TOTAL_BUDGET)).divide(BigInteger.TEN); From 3347f52dc7485e5a91a0c027289de7b64388a813 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Tue, 3 May 2022 13:18:39 +0545 Subject: [PATCH 047/112] added variable for repeated lines --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 89386a6b..25493ea4 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -242,12 +242,13 @@ public Address getBnUSDScore() { } } } + DictDB installmentRecord = installmentFundRecord.at(_wallet_address.toString()); return Map.of( "data", projectDetails, "project_count", projectDetails.size(), "total_amount", Map.of("ICX", totalAmountToBePaidICX, "bnUSD", totalAmountToBePaidbnUSD), - "withdraw_amount_icx", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.ICX, BigInteger.ZERO), - "withdraw_amount_bnUSD", installmentFundRecord.at(_wallet_address.toString()).getOrDefault(consts.bnUSD, BigInteger.ZERO), + "withdraw_amount_icx", installmentRecord.getOrDefault(consts.ICX, BigInteger.ZERO), + "withdraw_amount_bnUSD", installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO), "total_sponsor_bond", Map.of("ICX", totalSponsorBondICX, "bnUSD", totalSponsorBondbnUSD) ); } From d9367dda672e37b942c141af771f11c15e092a50 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Tue, 3 May 2022 13:18:46 +0545 Subject: [PATCH 048/112] added new returning variables in get method --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 25493ea4..be249884 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -205,7 +205,7 @@ public Address getBnUSDScore() { BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; BigInteger totalSponsorBondICX = BigInteger.ZERO; BigInteger totalSponsorBondbnUSD = BigInteger.ZERO; - List> projectDetails = new ArrayList<>(); + List> projectDetails = new ArrayList<>(); for (int i = 0; i < proposalsKeys.size(); i++) { String _ipfs_key = proposalsKeys.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); @@ -220,7 +220,7 @@ public Address getBnUSDScore() { BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); BigInteger depositedSponsorBond = ((BigInteger) proposal_details.get(consts.TOTAL_BUDGET)).divide(BigInteger.TEN); - Map project_details = Map.of( + Map project_details = Map.of( consts.IPFS_HASH, _ipfs_key, consts.TOKEN, flag, consts.TOTAL_BUDGET, totalBudget, From 6ac4d44933d2db97180d2ee5f8b206fb769b7649 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Tue, 3 May 2022 13:18:52 +0545 Subject: [PATCH 049/112] added berlin in deploy jar --- CPSTreasury/build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index 3be37cef..33f5d1f7 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -34,7 +34,11 @@ deployJar { sejong{ uri = 'https://sejong.net.solidwallet.io/api/v3' nid = 0x53 - + } + berlin{ + uri = 'https://berlin.net.solidwallet.io/api/v3' + nid = 0x7 + to = 'cx3e2a9648e4365added55bfa6a84e515d99f1bb67' } } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' From 6e4332d69bbe4b5fffd504f0d5faeb821fa6d2a4 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 6 May 2022 15:37:58 +0545 Subject: [PATCH 050/112] imports --- CPSTreasury/build.gradle | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index 33f5d1f7..c76c7b04 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -2,15 +2,14 @@ version = '0.9.1' dependencies { compileOnly 'foundation.icon:javaee-api:0.9.1' - implementation 'com.github.sink772:javaee-tokens:0.6.1' + implementation 'com.github.sink772:minimal-json:0.9.6' + implementation 'foundation.icon:javaee-scorex:0.5.2' testImplementation 'foundation.icon:javaee-unittest:0.9.2' - //testImplementation 'org.mockito:mockito-core:4.3.1' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' testImplementation('org.mockito:mockito-inline:4.3.1') - implementation 'foundation.icon:javaee-scorex:0.5.2' } From c7a27f2853245ad3600d0f1f2572773acc415fc1 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 6 May 2022 15:38:14 +0545 Subject: [PATCH 051/112] added `sponsorProjects` and `contributorProjects` --- .../cps/score/cpstreasury/CPSTreasury.java | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index be249884..b19e01f8 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -46,7 +46,8 @@ public class CPSTreasury extends ProposalData { private static final String ACTIVE = "active"; private static final String DISQUALIFIED = "disqualified"; private static final String COMPLETED = "completed"; - + private static final String CONTRIBUTOR_PROJECTS = "contributor_projects"; + private static final String SPONSOR_PROJECTS = "sponsor_projects"; private final VarDB id = Context.newVarDB(ID, String.class); private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); @@ -57,6 +58,8 @@ public class CPSTreasury extends ProposalData { private final VarDB
cpfTreasuryScore = Context.newVarDB(CPF_TREASURY_SCORE, Address.class); private final VarDB
cpsScore = Context.newVarDB(CPS_SCORE, Address.class); private final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); + private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS, String.class); + private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS, String.class); public CPSTreasury() { } @@ -106,6 +109,8 @@ private void addRecord(ProposalAttributes _proposal) { String ipfs_hash = _proposal.ipfs_hash; Context.require(!proposalExists(ipfs_hash), TAG + ": Already have this project"); proposalsKeys.add(ipfs_hash); + sponsorProjects.at(_proposal.sponsor_address).add(ipfs_hash); + contributorProjects.at(_proposal.contributor_address).add(ipfs_hash); String proposalPrefix = proposalPrefix(ipfs_hash); addDataToProposalDB(_proposal, proposalPrefix); proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); @@ -197,6 +202,23 @@ public Address getBnUSDScore() { "withdraw_amount_bnUSD", installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO)); } + @External + public List getContributorProjects(Address address){ + List contributorProjects = new ArrayList<>(); + for (int i = 0; i < this.contributorProjects.at(address.toString()).size(); i++){ + contributorProjects.add(this.contributorProjects.at(address.toString()).get(i)); + } + return contributorProjects; + } + + @External + public List getSponsorProjects(Address address){ + List sponsorProjects = new ArrayList<>(); + for (int i = 0; i < this.sponsorProjects.at(address.toString()).size(); i++){ + sponsorProjects.add(this.sponsorProjects.at(address.toString()).get(i)); + } + return sponsorProjects; + } @External(readonly = true) public Map get_sponsor_projected_fund(Address _wallet_address) { @@ -437,6 +459,19 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { } } +// for migration into java contract + @External + public void updateSponsorAndContributorProjects(){ + for (int i = 0; i < proposalsKeys.size(); i++){ + String proposalKey = proposalsKeys.get(i); + String proposalPrefix = proposalPrefix(proposalKey); + Address contributorAddress = getContributorAddress(proposalPrefix); + Address sponsorAddress = getSponsorAddress(proposalPrefix); + contributorProjects.at(contributorAddress.toString()).add(proposalKey); + sponsorProjects.at(sponsorAddress.toString()).add(proposalKey); + } + } + public T callScore(Class t, Address address, String method, Object... params) { return Context.call(t, address, method, params); } From 1660e01bf76888df4da1b61dc62afe6defb9e6fe Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 6 May 2022 15:43:29 +0545 Subject: [PATCH 052/112] added `readonly = true` on public get methods --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index b19e01f8..117505e0 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -202,7 +202,7 @@ public Address getBnUSDScore() { "withdraw_amount_bnUSD", installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO)); } - @External + @External(readonly = true) public List getContributorProjects(Address address){ List contributorProjects = new ArrayList<>(); for (int i = 0; i < this.contributorProjects.at(address.toString()).size(); i++){ @@ -211,7 +211,7 @@ public List getContributorProjects(Address address){ return contributorProjects; } - @External + @External(readonly = true) public List getSponsorProjects(Address address){ List sponsorProjects = new ArrayList<>(); for (int i = 0; i < this.sponsorProjects.at(address.toString()).size(); i++){ From 08d9fd5972f8cf9c77ea6ff0043d8bc37337e930 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 2 Sep 2022 12:54:08 +0545 Subject: [PATCH 053/112] setup for integration tests --- .gitignore | 11 + CPFTreasury/build.gradle | 2 + .../cps/score/cpftreasury/CPFTreasury.java | 32 +- CPSTreasury/build.gradle | 43 +- .../score/cpstreasury/CPSTreasuryIntTest.java | 40 ++ .../cps/score/cpstreasury/CPSTreasury.java | 27 +- build.gradle | 81 ++- docker-compose.yml | 13 + score-client/build.gradle | 22 + .../java/foundation/icon/jsonrpc/Address.java | 134 +++++ .../icon/jsonrpc/IconJsonModule.java | 454 ++++++++++++++++ .../icon/jsonrpc/JsonrpcClient.java | 271 ++++++++++ .../SendTransactionParamSerializer.java | 95 ++++ .../jsonrpc/model/AbstractTransaction.java | 76 +++ .../icon/jsonrpc/model/CallData.java | 37 ++ .../icon/jsonrpc/model/CallParam.java | 52 ++ .../icon/jsonrpc/model/DeployData.java | 64 +++ .../foundation/icon/jsonrpc/model/Hash.java | 56 ++ .../jsonrpc/model/SendTransactionParam.java | 64 +++ .../icon/jsonrpc/model/TransactionParam.java | 61 +++ .../icon/jsonrpc/model/TransactionResult.java | 173 ++++++ .../icon/score/client/DefaultScoreClient.java | 510 ++++++++++++++++++ .../icon/score/client/RevertedException.java | 29 + .../icon/score/client/ScoreClient.java | 28 + .../score/client/ScoreClientProcessor.java | 425 +++++++++++++++ .../icon/score/client/ScoreInterface.java | 29 + .../score/client/ScoreInterfaceProcessor.java | 282 ++++++++++ score-lib/build.gradle | 34 ++ settings.gradle | 13 +- test-lib/build.gradle | 33 ++ test-lib/conf/env.props | 6 + test-lib/conf/godWallet.json | 22 + .../icon/cps/score/test/integration/CPS.java | 50 ++ .../cps/score/test/integration/CPSClient.java | 25 + .../cps/score/test/integration/CPSUtils.java | 4 + .../icon/cps/score/test/integration/Env.java | 93 ++++ .../integration/ScoreIntegrationTest.java | 224 ++++++++ 37 files changed, 3599 insertions(+), 16 deletions(-) create mode 100644 CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java create mode 100644 docker-compose.yml create mode 100644 score-client/build.gradle create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/Address.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/IconJsonModule.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/JsonrpcClient.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/SendTransactionParamSerializer.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/model/AbstractTransaction.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/model/CallData.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/model/CallParam.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/model/DeployData.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/model/Hash.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/model/SendTransactionParam.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionParam.java create mode 100644 score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionResult.java create mode 100644 score-client/src/main/java/foundation/icon/score/client/DefaultScoreClient.java create mode 100644 score-client/src/main/java/foundation/icon/score/client/RevertedException.java create mode 100644 score-client/src/main/java/foundation/icon/score/client/ScoreClient.java create mode 100644 score-client/src/main/java/foundation/icon/score/client/ScoreClientProcessor.java create mode 100644 score-client/src/main/java/foundation/icon/score/client/ScoreInterface.java create mode 100644 score-client/src/main/java/foundation/icon/score/client/ScoreInterfaceProcessor.java create mode 100644 score-lib/build.gradle create mode 100644 test-lib/build.gradle create mode 100644 test-lib/conf/env.props create mode 100644 test-lib/conf/godWallet.json create mode 100644 test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java create mode 100644 test-lib/src/main/java/community/icon/cps/score/test/integration/CPSClient.java create mode 100644 test-lib/src/main/java/community/icon/cps/score/test/integration/CPSUtils.java create mode 100644 test-lib/src/main/java/community/icon/cps/score/test/integration/Env.java create mode 100644 test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java diff --git a/.gitignore b/.gitignore index e5271034..a2c5c73d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,15 @@ lib CPSTreasury.iml CPFTreasury/build CPSTreasury/build +gochain-local/ +goloop/ +CPSTreasury/.DS_Store +CPSTreasury/src/.DS_Store +.DS_Store +score-client/build +score-lib/build +test-lib/build +testinteg/build + + diff --git a/CPFTreasury/build.gradle b/CPFTreasury/build.gradle index f0d0d9f6..f3ae9c14 100644 --- a/CPFTreasury/build.gradle +++ b/CPFTreasury/build.gradle @@ -2,6 +2,8 @@ version = '0.9.1' dependencies { compileOnly 'foundation.icon:javaee-api:0.9.1' + implementation project(':score-lib') + implementation 'com.github.sink772:javaee-tokens:0.6.1' implementation 'com.github.sink772:minimal-json:0.9.6' diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java index dd2b8692..16966f43 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java @@ -16,20 +16,19 @@ import static community.icon.cps.score.cpftreasury.Constants.*; import static community.icon.cps.score.cpftreasury.Validations.validateAdmins; import static community.icon.cps.score.cpftreasury.Validations.validateCpsScore; +import community.icon.cps.score.lib.interfaces.CPFTreasuryInterface; -public class CPFTreasury extends SetterGetter { - - private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); - private final DictDB proposalBudgets = Context.newDictDB(PROPOSAL_BUDGETS, BigInteger.class); - private final VarDB treasuryFund = Context.newVarDB(TREASURY_FUND, BigInteger.class); - private final VarDB treasuryFundbnUSD = Context.newVarDB(TREASURY_FUND_BNUSD, BigInteger.class); - +public class CPFTreasury extends SetterGetter implements CPFTreasuryInterface { public static final VarDB
cpsTreasuryScore = Context.newVarDB(CPS_TREASURY_SCORE, Address.class); public static final VarDB
cpsScore = Context.newVarDB(CPS_SCORE, Address.class); public static final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); public static final VarDB
dexScore = Context.newVarDB(DEX_SCORE, Address.class); public static final VarDB
sICXScore = Context.newVarDB(SICX_SCORE, Address.class); public static final VarDB
routerScore = Context.newVarDB(ROUTER_SCORE, Address.class); + private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); + private final DictDB proposalBudgets = Context.newDictDB(PROPOSAL_BUDGETS, BigInteger.class); + private final VarDB treasuryFund = Context.newVarDB(TREASURY_FUND, BigInteger.class); + private final VarDB treasuryFundbnUSD = Context.newVarDB(TREASURY_FUND_BNUSD, BigInteger.class); private final VarDB swapState = Context.newVarDB(SWAP_STATE, Integer.class); private final VarDB swapCount = Context.newVarDB(SWAP_COUNT, Integer.class); @@ -42,12 +41,14 @@ private boolean proposalExists(String ipfsKey) { return proposalBudgets.get(ipfsKey) != null; } + @Override @External(readonly = true) public String name() { return TAG; } + @Override @External public void setMaximumTreasuryFundIcx(BigInteger _value) { validateAdmins(); @@ -59,6 +60,7 @@ public void setMaximumTreasuryFundIcx(BigInteger _value) { * * @param _value: value in loop */ + @Override @External public void setMaximumTreasuryFundBnusd(BigInteger _value) { validateAdmins(); @@ -75,6 +77,7 @@ private void burn(BigInteger amount) { * * @return map of ICX and bnUSD amount */ + @Override @External(readonly = true) public Map get_total_funds() { return Map.of(ICX, Context.getBalance(Context.getAddress()), @@ -85,6 +88,7 @@ private BigInteger getTotalFundBNUSD() { return (BigInteger) Context.call(balancedDollar.get(), "balanceOf", Context.getAddress()); } + @Override @External(readonly = true) public Map get_remaining_swap_amount() { BigInteger maxCap = treasuryFundbnUSD.get(); @@ -98,6 +102,7 @@ private void returnFundAmount(Address address, BigInteger value) { FundReturned(address, "Sponsor Bond amount " + value + " " + bnUSD + " Returned to CPF Treasury."); } + @Override @External public void transfer_proposal_fund_to_cps_treasury(String _ipfs_key, int _total_installment_count, Address _sponsor_address, Address _contributor_address, @@ -131,6 +136,7 @@ public void transfer_proposal_fund_to_cps_treasury(String _ipfs_key, int _total_ ProposalFundTransferred(_ipfs_key, "Successfully transferred " + totalTransfer + " " + token_flag + " to CPS Treasury " + cpsTreasuryScore.get()); } + @Override @External public void update_proposal_fund(String _ipfs_key, @Optional String _flag, @Optional BigInteger _added_budget, @Optional int _total_installment_count) { @@ -174,6 +180,7 @@ private void disqualifyProposalFund(String ipfsKey, BigInteger value) { ProposalDisqualified(ipfsKey, "Proposal disqualified. " + value + " " + bnUSD + " is returned back to Treasury."); } + @Override @External @Payable public void add_fund() { @@ -206,6 +213,7 @@ private void swapTokens(Address _from, Address _to, BigInteger _amount) { Context.call(_from, "transfer", dexScore.get(), _amount, swapData.toString().getBytes()); } + @Override @External public void swapIcxBnusd(BigInteger amount) { Address[] path = new Address[]{sICXScore.get(), balancedDollar.get()}; @@ -213,6 +221,7 @@ public void swapIcxBnusd(BigInteger amount) { Context.call(amount, routerScore.get(), "route", params); } + @Override @External public void swap_tokens(int _count) { validateCpsScore(); @@ -247,11 +256,13 @@ public void swap_tokens(int _count) { } } + @Override @External(readonly = true) public Map get_swap_state_status() { return Map.of("state", swapState.getOrDefault(0), "count", swapCount.getOrDefault(0)); } + @Override @External public void reset_swap_state() { Address cpsScoreAddress = cpsScore.get(); @@ -263,6 +274,7 @@ public void reset_swap_state() { swapCount.set(SwapReset); } + @Override @External(readonly = true) public Map get_proposal_details(@Optional int _start_index, @Optional int _end_index) { if (_end_index == 0) { @@ -294,6 +306,7 @@ public Map get_proposal_details(@Optional int _start_index, @Opt return Map.of("data", proposalsList, "count", count); } + @Override @External public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { Address bnUSDScore = balancedDollar.get(); @@ -340,6 +353,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { } } + @Override @Payable public void fallback() { if (Context.getCaller().equals(dexScore.get())) { @@ -351,18 +365,22 @@ public void fallback() { //EventLogs + @Override @EventLog(indexed = 1) public void FundReturned(Address _sponsor_address, String note) { } + @Override @EventLog(indexed = 1) public void ProposalFundTransferred(String _ipfs_key, String note) { } + @Override @EventLog(indexed = 1) public void ProposalDisqualified(String _ipfs_key, String note) { } + @Override @EventLog(indexed = 1) public void FundReceived(Address _sponsor_address, String note) { } diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index c76c7b04..48c3694e 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -3,14 +3,17 @@ version = '0.9.1' dependencies { compileOnly 'foundation.icon:javaee-api:0.9.1' + implementation project(':score-lib') implementation 'com.github.sink772:minimal-json:0.9.6' implementation 'foundation.icon:javaee-scorex:0.5.2' - + testImplementation project(':test-lib') testImplementation 'foundation.icon:javaee-unittest:0.9.2' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' testImplementation('org.mockito:mockito-inline:4.3.1') - + intTestImplementation "foundation.icon:icon-sdk:2.1.0" + intTestImplementation project(":score-client") + intTestAnnotationProcessor project(":score-client") } optimizedJar { @@ -42,10 +45,40 @@ deployJar { } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' - parameters { - } + parameters {} } test { - useJUnitPlatform() + useJUnitPlatform { + excludeTags("integration") + } +} + +sourceSets { + intTest { + java.srcDirs = [file('src/intTest/java')] + + compileClasspath += sourceSets.main.output + configurations.testRuntime + runtimeClasspath += output + compileClasspath + } } + +task integrationTest(type: Test) { + useJUnitPlatform() + + + rootProject.allprojects { + if (it.getTasks().findByName('optimizedJar')) { + dependsOn(it.getTasks().getByName('optimizedJar')) + } + } + + options { + testLogging.showStandardStreams = true + description = 'Runs integration tests.' + group = 'verification' + + testClassesDirs = sourceSets.intTest.output.classesDirs + classpath = sourceSets.intTest.runtimeClasspath + } +} \ No newline at end of file diff --git a/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java b/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java new file mode 100644 index 00000000..2e2119a2 --- /dev/null +++ b/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java @@ -0,0 +1,40 @@ +package community.icon.cps.score.cpstreasury; + +import community.icon.cps.score.lib.interfaces.CPFTreasuryInterfaceScoreClient; +import community.icon.cps.score.lib.interfaces.CPSTreasuryInterfaceScoreClient; +import community.icon.cps.score.test.integration.CPS; +import community.icon.cps.score.test.integration.ScoreIntegrationTest; +import foundation.icon.icx.Wallet; + +import org.junit.jupiter.api.*; + +import java.math.BigInteger; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class CPSTreasuryIntTest { + private static CPS cps; + private static Wallet tester; + private static Wallet owner; + + private static CPSTreasuryInterfaceScoreClient cpsTreasury; + private static CPFTreasuryInterfaceScoreClient cpfTreasury; + + @BeforeAll + static void setup() throws Exception { + tester = ScoreIntegrationTest.createWalletWithBalance(BigInteger.TEN.pow(24)); + cps = new CPS(); + cps.setupCPS(); + owner = cps.owner; + cpsTreasury = new CPSTreasuryInterfaceScoreClient(cps.cpsTreasury); + cpfTreasury = new CPFTreasuryInterfaceScoreClient(cps.cpfTreasury); + } + + @Test + void name(){ + System.out.println(cpsTreasury.name()); + System.out.println(cpfTreasury.name()); + System.out.println(cpsTreasury._address()); + System.out.println(cpfTreasury._address()); + } + +} diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 117505e0..5c5e8356 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -13,9 +13,11 @@ import java.util.List; import java.util.Map; +import community.icon.cps.score.lib.interfaces.CPSTreasuryInterface; + import community.icon.cps.score.cpstreasury.utils.consts; -public class CPSTreasury extends ProposalData { +public class CPSTreasury extends ProposalData implements CPSTreasuryInterface{ private static final String TAG = "CPS_TREASURY"; private static final String PROPOSAL_DB_PREFIX = "proposal"; @@ -64,11 +66,13 @@ public class CPSTreasury extends ProposalData { public CPSTreasury() { } + @Override @External(readonly = true) public String name() { return TAG; } + @Override @Payable public void fallback() { Context.revert(TAG + ": ICX can only be send by CPF Treasury Score"); @@ -121,39 +125,46 @@ private void addRecord(ProposalAttributes _proposal) { return proposalData.getDataFromProposalDB(_proposal_key); } + @Override @External public void setCpsScore(Address _score) { validateAdminScore(_score); cpsScore.set(_score); } + @Override @External(readonly = true) //Todo java convention in get methods?? public Address getCpsScore() { return cpsScore.get(); } + @Override @External public void setCpfTreasuryScore(Address _score) { validateAdminScore(_score); cpfTreasuryScore.set(_score); } + @Override @External(readonly = true) public Address getCpfTreasuryScore() { return cpfTreasuryScore.get(); } + @Override @External public void setBnUSDScore(Address _score) { validateAdminScore(_score); balancedDollar.set(_score); } + @Override @External public Address getBnUSDScore() { return balancedDollar.get(); } + @Override @External(readonly = true) public Map get_contributor_projected_fund(Address _wallet_address) { BigInteger totalAmountToBePaidICX = BigInteger.ZERO; @@ -202,6 +213,7 @@ public Address getBnUSDScore() { "withdraw_amount_bnUSD", installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO)); } + @Override @External(readonly = true) public List getContributorProjects(Address address){ List contributorProjects = new ArrayList<>(); @@ -211,6 +223,7 @@ public List getContributorProjects(Address address){ return contributorProjects; } + @Override @External(readonly = true) public List getSponsorProjects(Address address){ List sponsorProjects = new ArrayList<>(); @@ -220,6 +233,7 @@ public List getSponsorProjects(Address address){ return sponsorProjects; } + @Override @External(readonly = true) public Map get_sponsor_projected_fund(Address _wallet_address) { ProposalData proposalData = new ProposalData(); @@ -281,6 +295,7 @@ private void depositProposalFund(ProposalData.ProposalAttributes _proposals, Big consts.bnUSD + " fund from CPF"); } + @Override @External @Payable public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, BigInteger _added_sponsor_reward, @@ -310,6 +325,7 @@ public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, Big flag + "and Added time: " + _added_installment_count + " Successfully"); } + @Override @External public void send_installment_to_contributor(String _ipfs_key) { validateCpsScore(); @@ -343,6 +359,7 @@ public void send_installment_to_contributor(String _ipfs_key) { } } + @Override @External public void send_reward_to_sponsor(String _ipfs_key) { validateCpsScore(); @@ -372,6 +389,7 @@ public void send_reward_to_sponsor(String _ipfs_key) { flag + " sent to sponsor address."); } + @Override @External public void disqualify_project(String _ipfs_key) { validateCpsScore(); @@ -407,6 +425,7 @@ public void disqualify_project(String _ipfs_key) { } + @Override @External public void claim_reward() { BigInteger availableAmountICX = installmentFundRecord.at(Context.getCaller().toString()).getOrDefault(consts.ICX, BigInteger.ZERO); @@ -423,6 +442,7 @@ public void claim_reward() { } } + @Override @External public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { Context.require(_from.equals(cpfTreasuryScore.get()), TAG + "Only receiving from " + cpfTreasuryScore.get()); @@ -460,6 +480,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { } // for migration into java contract + @Override @External public void updateSponsorAndContributorProjects(){ for (int i = 0; i < proposalsKeys.size(); i++){ @@ -484,18 +505,22 @@ public void callScore(BigInteger amount, Address address, String method, Object. Context.call(amount, address, method, params); } + @Override @EventLog(indexed = 1) public void ProposalDisqualified(String _ipfs_key, String note) { } + @Override @EventLog(indexed = 1) public void ProposalFundDeposited(String _ipfs_key, String note) { } + @Override @EventLog(indexed = 1) public void ProposalFundSent(Address _receiver_address, String note) { } + @Override @EventLog(indexed = 1) public void ProposalFundWithdrawn(Address _receiver_address, String note) { } diff --git a/build.gradle b/build.gradle index 8fa0cddd..2fd7aebe 100644 --- a/build.gradle +++ b/build.gradle @@ -3,18 +3,72 @@ buildscript { mavenCentral() } dependencies { - classpath 'foundation.icon:gradle-javaee-plugin:0.8.0' + classpath "foundation.icon:gradle-javaee-plugin:0.8.1" } } +def scoreIntegrationTest = new HashMap() + +task buildContracts(type: Exec) { + workingDir "$projectDir/" + commandLine './gradlew', 'optimizedJar' +} + +//apply plugin: 'deploy-contracts' +//deployCPSContracts { +// envs { +// local { +// env = "local" +// } +// berlin { +// env = "berlin" +// configFile = "contracts-sample.json" +// keystore = rootProject.findProperty('keystoreName') ?: '' +// password = rootProject.findProperty('keystorePass') ?: '' +// } +// sejong { +// env = "sejong" +// configFile = "contracts-sample.json" +// keystore = rootProject.findProperty('keystoreName') ?: '' +// password = rootProject.findProperty('keystorePass') ?: '' +// } +// } +//} + + +//executeBalancedActions { +// contractAddressFile = "sample.json" +// propertiesFile = "sample.properties" +// actionsFile = "actions-sample.json" +// keystore = rootProject.findProperty('keystoreName') ?: '' +// password = rootProject.findProperty('keystorePass') ?: '' +//} + + subprojects { repositories { mavenCentral() } apply plugin: 'java' + apply plugin: 'jacoco' apply plugin: 'foundation.icon.javaee' + sourceSets { + intTest { + compileClasspath += sourceSets.main.output + runtimeClasspath += sourceSets.main.output + java { + } + } + } + + configurations { + intTestImplementation.extendsFrom testImplementation + intTestAnnotationProcessor.extendsFrom testAnnotationProcessor + intTestRuntimeOnly.extendsFrom testRuntimeOnly + } + java { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 @@ -24,4 +78,29 @@ subprojects { compileJava { options.compilerArgs += ['-parameters'] } + + tasks.named('test') { + // Use JUnit Platform for unit tests. + useJUnitPlatform() + } + + scoreIntegrationTest.put('env.props', new File(project(':test-lib').projectDir, 'conf/env.props')) + + afterEvaluate { project -> + scoreIntegrationTest.put(project.name, project.getTasks().getByName("optimizedJar").outputJarName) + } + + tasks.named("assemble") { + if (project.tasks.findByName("compileIntTestJava")) { + finalizedBy(project.tasks.getByName("compileIntTestJava")) + } + } + + gradle.taskGraph.whenReady { taskGraph -> + taskGraph.getAllTasks().eachWithIndex { task, n -> + if (task.name == 'integrationTest') { + scoreIntegrationTest.each { key, val -> task.systemProperty key, val } + } + } + } } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..9375516f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +version: "3.7" +services: + gochain-iconee: + container_name: gochain-iconee + image: public.ecr.aws/f5d2t1f5/goloop-gochain-icon:latest + env_file: + - ./gochain-local/data/single/iconee.env + volumes: + - ./gochain-local/data/single:/goloop/data + - ./gochain-local/data/governance:/goloop/data/gov + - ./gochain-local/chain:/testsuite/chain + ports: + - "9082:9082" \ No newline at end of file diff --git a/score-client/build.gradle b/score-client/build.gradle new file mode 100644 index 00000000..edbc0eda --- /dev/null +++ b/score-client/build.gradle @@ -0,0 +1,22 @@ +apply plugin: 'java-library' + +optimizedJar.enabled = false + + +dependencies { + implementation("foundation.icon:javaee-annotation-processor:0.9.0") + implementation("com.squareup:javapoet:1.12.1") + implementation("foundation.icon:javaee-api:0.9.0") + implementation("foundation.icon:icon-sdk:2.0.0") + implementation("com.fasterxml.jackson.core:jackson-databind:2.9.6") + implementation("com.squareup.okhttp3:okhttp:3.11.0") + implementation("org.bouncycastle:bcprov-jdk15on:1.60") + + testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.2") + testImplementation("org.junit.jupiter:junit-jupiter-params:5.7.2") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.2") +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/Address.java b/score-client/src/main/java/foundation/icon/jsonrpc/Address.java new file mode 100644 index 00000000..48bea738 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/Address.java @@ -0,0 +1,134 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import foundation.icon.icx.Wallet; + +import java.util.Arrays; + +public class Address extends score.Address { + public enum Type { + EOA("hx", 0x0), + CONTRACT("cx", 0x1); + String str; + byte value; + Type(String str, int value) { + this.str = str; + this.value = (byte)value; + } + String str() { + return str; + } + byte value() { + return value; + } + static Type of(byte value) { + for(Type type : values()) { + if (type.value == value) { + return type; + } + } + throw new IllegalArgumentException(); + } + static Type of(String str) { + for(Type type : values()) { + if (type.str.equals(str)) { + return type; + } + } + throw new IllegalArgumentException(); + } + } + public static final int LENGTH = 21; + public static final int BODY_LENGTH = LENGTH - 1; + private final Type type; + private final String str; + private final byte[] bytes; + + @JsonCreator + public Address(String str) { + this(parse(str)); + } + + public Address(byte[] bytes) throws IllegalArgumentException { + super(bytes); + if (bytes == null) { + throw new IllegalArgumentException("raw could not be null"); + } + if (bytes.length != LENGTH) { + throw new IllegalArgumentException("invalid length"); + } + type = Type.of(bytes[0]); + this.bytes = bytes; + this.str = type.str() + IconJsonModule.bytesToHex(bytes).substring(2); + } + + public Address(Type type, byte[] body) throws IllegalArgumentException { + this(concat(type.value(), body)); + } + + public boolean isContract() { + return Type.CONTRACT.equals(type); + } + + public static byte[] concat(byte type, byte[] body) { + byte[] copy = new byte[LENGTH]; + copy[0] = type; + System.arraycopy(body, 0, copy, 1, BODY_LENGTH); + return copy; + } + + public byte[] toByteArray() { + return Arrays.copyOf(bytes, LENGTH); + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof score.Address && toString().equals(obj.toString())); + } + + @JsonValue + @Override + public String toString() { + return str; + } + + public static byte[] parse(String str) { + if (str == null) { + throw new IllegalArgumentException("string could not be null"); + } + if (str.length() != LENGTH * 2) { + throw new IllegalArgumentException("invalid length"); + } + byte[] bytes = new byte[LENGTH]; + bytes[0] = Type.of(str.substring(0, 2)).value(); + System.arraycopy(IconJsonModule.hexToBytes(str.substring(2)), 0, bytes, 1, BODY_LENGTH); + return bytes; + } + + public static Address of(Wallet wallet) { + return of(wallet.getAddress()); + } + + private static Address of(foundation.icon.icx.data.Address address) { + return new Address(address.toString()); + } + +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/IconJsonModule.java b/score-client/src/main/java/foundation/icon/jsonrpc/IconJsonModule.java new file mode 100644 index 00000000..fc81edc8 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/IconJsonModule.java @@ -0,0 +1,454 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.core.util.VersionUtil; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.databind.util.Converter; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.function.Function; + +public class IconJsonModule extends SimpleModule { + public final static Version VERSION = VersionUtil.parseVersion( + "0.1.0", "foundation.icon", "javaee-score-client" + ); + + public static final String BOOLEAN_TRUE = "0x1"; + public static final String BOOLEAN_FALSE = "0x0"; + public static final String HEX_PREFIX = "0x"; + public static final String NEG_HEX_PREFIX = "-0x"; + private final boolean isIncludeNonNull; + + public static final char[] HEX_CODES = "0123456789abcdef".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + if (bytes == null) { + return ""; + } + StringBuilder r = new StringBuilder(bytes.length * 2); + for (byte b : bytes) { + r.append(HEX_CODES[(b >> 4) & 0xF]); + r.append(HEX_CODES[(b & 0xF)]); + } + return r.toString(); + } + + public static byte[] hexToBytes(String hexString) { + if (hexString == null) { + return null; + } + if (hexString.length() % 2 > 0) { + throw new IllegalArgumentException("hex cannot has odd length"); + } + int l = hexString.length()/2; + int j = 0; + byte[] bytes = new byte[l]; + for (int i = 0; i < l; i++) { + bytes[i] = (byte)((Character.digit(hexString.charAt(j++), 16) << 4) | + Character.digit(hexString.charAt(j++), 16) & 0xFF); + } + return bytes; + } + + public IconJsonModule() { + super(VERSION); + this.isIncludeNonNull = true; + init(); + } + + public IconJsonModule(boolean isIncludeNonNull) { + super(VERSION); + this.isIncludeNonNull = isIncludeNonNull; + init(); + } + + private void init() { + addSerializer(char.class, CharSerializer.CHAR); + addSerializer(Character.class, CharSerializer.CHAR); + addSerializer(byte.class, NumberSerializer.BYTE); + addSerializer(Byte.class, NumberSerializer.BYTE); + addSerializer(long.class, NumberSerializer.LONG); + addSerializer(Long.class, NumberSerializer.LONG); + addSerializer(int.class, NumberSerializer.INTEGER); + addSerializer(Integer.class, NumberSerializer.INTEGER); + addSerializer(short.class, NumberSerializer.SHORT); + addSerializer(Short.class, NumberSerializer.SHORT); + addSerializer(BigInteger.class, NumberSerializer.BIG_INTEGER); + addSerializer(boolean.class, BooleanSerializer.BOOLEAN); + addSerializer(Boolean.class, BooleanSerializer.BOOLEAN); + addSerializer(byte[].class, ByteArraySerializer.BYTE_ARRAY); + addSerializer(score.Address.class, AddressSerializer.SCORE_ADDRESS); +// addSerializer(foundation.icon.icx.data.Address.class, AddressSerializer.SDK_ADDRESS); + + addDeserializer(char.class, CharDeserializer.CHAR); + addDeserializer(Character.class, CharDeserializer.CHAR); + addDeserializer(byte.class, NumberDeserializer.BYTE); + addDeserializer(Byte.class, NumberDeserializer.BYTE); + addDeserializer(long.class, NumberDeserializer.LONG); + addDeserializer(Long.class, NumberDeserializer.LONG); + addDeserializer(int.class, NumberDeserializer.INTEGER); + addDeserializer(Integer.class, NumberDeserializer.INTEGER); + addDeserializer(short.class, NumberDeserializer.SHORT); + addDeserializer(Short.class, NumberDeserializer.SHORT); + addDeserializer(BigInteger.class, NumberDeserializer.BIG_INTEGER); + addDeserializer(boolean.class, BooleanDeserializer.BOOLEAN); + addDeserializer(Boolean.class, BooleanDeserializer.BOOLEAN); + addDeserializer(byte[].class, ByteArrayDeserializer.BYTE_ARRAY); + addDeserializer(score.Address.class, AddressDeserializer.SCORE_ADDRESS); +// addDeserializer(foundation.icon.icx.data.Address.class, AddressDeserializer.SDK_ADDRESS); + } + + @Override + public void setupModule(SetupContext context) { + super.setupModule(context); + if (isIncludeNonNull) { + JsonInclude.Value value = JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL); + context.configOverride(Long.class).setInclude(value); + context.configOverride(Integer.class).setInclude(value); + context.configOverride(Short.class).setInclude(value); + context.configOverride(BigInteger.class).setInclude(value); + context.configOverride(Boolean.class).setInclude(value); + context.configOverride(byte[].class).setInclude(value); + } + } + + public static class NumberSerializer extends JsonSerializer implements Converter { + public static final NumberSerializer BYTE = new NumberSerializer<>(); + public static final NumberSerializer SHORT = new NumberSerializer<>(); + public static final NumberSerializer INTEGER = new NumberSerializer<>(); + public static final NumberSerializer LONG = new NumberSerializer<>(); + public static final NumberSerializer BIG_INTEGER = new NumberSerializer<>(); + + @Override + public String convert(T t) { + BigInteger bi; + if (t instanceof BigInteger) { + bi = (BigInteger) t; + } else { + bi = BigInteger.valueOf(t.longValue()); + } + String prefix = (bi.signum() == -1) ? NEG_HEX_PREFIX : HEX_PREFIX; + return prefix + bi.abs().toString(16); + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(new TypeReference(){}); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(convert(value)); + } + } + + public static class CharSerializer extends JsonSerializer implements Converter { + public static final CharSerializer CHAR = new CharSerializer(); + + @Override + public String convert(Character value) { + return NumberSerializer.INTEGER.convert((int)value); + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(Character.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public void serialize(Character value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(convert(value)); + } + } + + public static class BooleanSerializer extends JsonSerializer implements Converter { + public static final BooleanSerializer BOOLEAN = new BooleanSerializer(); + + @Override + public String convert(Boolean value) { + return value ? BOOLEAN_TRUE : BOOLEAN_FALSE; + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(Boolean.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value != null) { + gen.writeString(convert(value)); + } + } + } + + public static class ByteArraySerializer extends JsonSerializer implements Converter { + public static final ByteArraySerializer BYTE_ARRAY = new ByteArraySerializer(); + + @Override + public void serialize(byte[] value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(convert(value)); + } + + @Override + public String convert(byte[] value) { + return HEX_PREFIX + bytesToHex(value); + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructArrayType(byte.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + } + + public static class AddressSerializer extends JsonSerializer implements Converter { + public static final AddressSerializer SCORE_ADDRESS = new AddressSerializer<>(); + public static final AddressSerializer SDK_ADDRESS = new AddressSerializer<>(); + + @Override + public String convert(T value) { + return value.toString(); + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(new TypeReference(){}); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public void serialize(T address, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(convert(address)); + } + } + + public static class NumberDeserializer extends JsonDeserializer implements Converter{ + public static final NumberDeserializer BYTE = new NumberDeserializer<>(BigInteger::byteValue); + public static final NumberDeserializer SHORT = new NumberDeserializer<>(BigInteger::shortValue); + public static final NumberDeserializer INTEGER = new NumberDeserializer<>(BigInteger::intValue); + public static final NumberDeserializer LONG = new NumberDeserializer<>(BigInteger::longValue); + public static final NumberDeserializer BIG_INTEGER = new NumberDeserializer<>(bi -> bi); + + private final Function parseFunc; + + public NumberDeserializer(Function parseFunc) { + this.parseFunc = parseFunc; + } + + @Override + public T convert(String s) { + if (s.startsWith(HEX_PREFIX)) { + return parseFunc.apply(new BigInteger(s.substring(2), 16)); + } else if (s.startsWith(NEG_HEX_PREFIX)) { + return parseFunc.apply(new BigInteger(s.substring(3), 16).negate()); + } else { +// throw new IllegalArgumentException(String.format("invalid prefix loc:%s", p.getCurrentLocation().toString())); + return parseFunc.apply(new BigInteger(s, 16)); + } + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(new TypeReference(){}); + } + + @SuppressWarnings("unchecked") + @Override + public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + if (p.currentToken().isNumeric()) { + return parseFunc.apply(p.getBigIntegerValue()); + } else { + return convert(p.getValueAsString()); + } + } + } + + public static class CharDeserializer extends JsonDeserializer implements Converter { + public static final CharDeserializer CHAR = new CharDeserializer(); + + @Override + public Character convert(String value) { + return (char) NumberDeserializer.INTEGER.convert(value).intValue(); + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(Boolean.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public Character deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + if (p.currentToken().isNumeric()) { + return (char)p.getIntValue(); + } else { + return convert(p.getValueAsString()); + } + } + } + + public static class BooleanDeserializer extends JsonDeserializer implements Converter { + public static final BooleanDeserializer BOOLEAN = new BooleanDeserializer(); + + @Override + public Boolean convert(String value) { + if (BOOLEAN_TRUE.equals(value)) { + return Boolean.TRUE; + } else if (BOOLEAN_FALSE.equals(value)) { + return Boolean.FALSE; + } + throw new IllegalArgumentException("invalid value:"+value); + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(Boolean.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + try{ + return convert(p.getValueAsString()); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException( + String.format("fail to deserialize loc:%s err:%s", + p.getCurrentLocation().toString(), e.getMessage()),e); + } + } + } + + public static class ByteArrayDeserializer extends JsonDeserializer implements Converter{ + public static final ByteArrayDeserializer BYTE_ARRAY = new ByteArrayDeserializer(); + + @Override + public byte[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + try{ + return convert(p.getValueAsString()); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException( + String.format("fail to deserialize loc:%s err:%s", + p.getCurrentLocation().toString(), e.getMessage()),e); + } + } + + @Override + public byte[] convert(String s) { + if (s.length() % 2 == 0) { + if (s.startsWith(HEX_PREFIX)) { + s = s.substring(2); + } + return hexToBytes(s); + } else { + throw new IllegalArgumentException("hex string length must be even"); + } + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructArrayType(byte.class); + } + } + + public static class AddressDeserializer extends JsonDeserializer implements Converter { + public static final AddressDeserializer SCORE_ADDRESS = new AddressDeserializer<>(Address::new); + public static final AddressDeserializer SDK_ADDRESS = new AddressDeserializer<>(foundation.icon.icx.data.Address::new); + + private final Function parseFunc; + + public AddressDeserializer(Function parseFunc) { + this.parseFunc = parseFunc; + } + + @Override + public T convert(String value) { + return parseFunc.apply(value); + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(String.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(new TypeReference(){}); + } + + @Override + public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + return convert(p.getValueAsString()); + } + } + +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/JsonrpcClient.java b/score-client/src/main/java/foundation/icon/jsonrpc/JsonrpcClient.java new file mode 100644 index 00000000..4975e581 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/JsonrpcClient.java @@ -0,0 +1,271 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.deser.std.NumberDeserializers; +import okhttp3.Headers; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.BufferedSink; + +import java.io.IOException; + +public class JsonrpcClient { + public static MediaType APPLICATION_JSON = MediaType.parse("application/json"); + + protected final String endpoint; + protected final OkHttpClient httpClient; + protected final ObjectMapper mapper; + protected Headers customHeaders; + protected boolean dumpJson; + + public JsonrpcClient(String endpoint) { + this(endpoint, new OkHttpClient.Builder().build()); + } + + public JsonrpcClient(String endpoint, OkHttpClient httpClient) { + this(endpoint, httpClient, new ObjectMapper()); + } + + public JsonrpcClient(String endpoint, ObjectMapper mapper) { + this(endpoint, new OkHttpClient.Builder().build(), mapper); + } + + public JsonrpcClient(String endpoint, OkHttpClient httpClient, ObjectMapper mapper) { + this.endpoint = endpoint; + this.httpClient = httpClient; + this.mapper = mapper; + } + + public String endpoint() { + return endpoint; + } + + public OkHttpClient httpClient() { + return httpClient; + } + + public ObjectMapper mapper() { + return mapper; + } + + public boolean isDumpJson() { + return dumpJson; + } + + public void setDumpJson(boolean dumpJson) { + this.dumpJson = dumpJson; + } + + public Headers getCustomHeaders() { + return customHeaders; + } + + public void setCustomHeaders(Headers customHeaders) { + this.customHeaders = customHeaders; + } + + private Headers.Builder customHeadersBuilder() { + return customHeaders == null ? new Headers.Builder() : customHeaders.newBuilder(); + } + + public void addCustomHeader(String name) { + customHeaders = customHeadersBuilder().add(name).build(); + } + + public void addCustomHeader(String name, String value) { + customHeaders = customHeadersBuilder().add(name, value).build(); + } + + public void setCustomHeader(String name, String value) { + customHeaders = customHeadersBuilder().set(name, value).build(); + } + + public Object request(String method, Object param) { + return request(Object.class, method, param); + } + + public T request(Class resultType, String method, Object params) { + return request(mapper.getTypeFactory().constructType(resultType), method, params); + } + + public T request(TypeReference resultType, String method, Object params) { + return request(mapper.getTypeFactory().constructType(resultType), method, params); + } + + public T request(JavaType resultType, String method, Object params) { + Request.Builder builder = new Request.Builder() + .url(endpoint) + .post(new JsonrpcRequest(method, params, mapper, dumpJson)); + if (customHeaders != null) { + builder.headers(customHeaders); + } + return request(builder.build(), resultType); + } + + protected T request(Request request, JavaType resultType) { + Response response = null; + try { + response = httpClient.newCall(request).execute(); + } catch (IOException e) { + throw new RuntimeException(e); + } + ResponseBody responseBody = response.body(); + if (responseBody != null) { + JsonrpcResponse jsonrpcResponse = null; + try { + String json = responseBody.string(); + if (dumpJson) { + System.out.println(json); + } + jsonrpcResponse = mapper.readValue(json, + mapper.getTypeFactory().constructParametricType(JsonrpcResponse.class, resultType)); + } catch (IOException e) { + throw new RuntimeException(e); + } + JsonrpcError error = jsonrpcResponse.getError(); + if (error != null) { + throw error; + } + return jsonrpcResponse.result; + } else { + throw new RuntimeException("empty body"); + } + } + + public static class JsonrpcRequest extends RequestBody { + @JsonIgnore + ObjectMapper mapper; + @JsonIgnore + boolean dumpJson; + String jsonrpc = "2.0"; + @JsonSerialize(using = LongLikeSerializer.class) + @JsonDeserialize(using = NumberDeserializers.NumberDeserializer.class) + long id; + String method; + @JsonInclude(JsonInclude.Include.NON_NULL) + Object params; + + JsonrpcRequest(String method, Object params, ObjectMapper mapper, boolean dumpJson) { + this.id = System.currentTimeMillis(); + this.method = method; + this.params = params; + this.mapper = mapper; + this.dumpJson = dumpJson; + } + + @Override + public MediaType contentType() { + return APPLICATION_JSON; + } + + @Override + public void writeTo(BufferedSink bufferedSink) throws IOException { + if (dumpJson) { + byte[] bytes = mapper.writeValueAsBytes(this); + bufferedSink.write(bytes); + System.out.println(new String(bytes)); + } else { + mapper.writeValue(bufferedSink.outputStream(), this); + } + } + + public String getJsonrpc() { + return jsonrpc; + } + + public long getId() { + return id; + } + + public String getMethod() { + return method; + } + + public Object getParams() { + return params; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class JsonrpcResponse { + String jsonrpc = "2.0"; + @JsonSerialize(using = LongLikeSerializer.class) + @JsonDeserialize(using = NumberDeserializers.NumberDeserializer.class) + long id; + T result; + JsonrpcError error; + + public String getJsonrpc() { + return jsonrpc; + } + + public long getId() { + return id; + } + + public T getResult() { + return result; + } + + public JsonrpcError getError() { + return error; + } + } + + public static class JsonrpcError extends RuntimeException { + @JsonSerialize(using = LongLikeSerializer.class) + @JsonDeserialize(using = NumberDeserializers.NumberDeserializer.class) + private long code; + private String message; + private byte[] data; + + public long getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public byte[] getData() { + return data; + } + } + + public static class LongLikeSerializer extends JsonSerializer { + @Override + public void serialize(Long aLong, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeNumber(((Number) aLong).intValue()); + } + } +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/SendTransactionParamSerializer.java b/score-client/src/main/java/foundation/icon/jsonrpc/SendTransactionParamSerializer.java new file mode 100644 index 00000000..898ea823 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/SendTransactionParamSerializer.java @@ -0,0 +1,95 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import foundation.icon.jsonrpc.model.SendTransactionParam; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.StringJoiner; +import java.util.TreeSet; + +public class SendTransactionParamSerializer { + static final String PREFIX = "icx_sendTransaction."; + + static ObjectMapper iconMapper = new ObjectMapper(); + static { + iconMapper.registerModule(new IconJsonModule()); + iconMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + static ObjectMapper mapper = new ObjectMapper(); + + public static String serialize(SendTransactionParam sendTransactionParam) throws IOException { + return serialize(sendTransactionParam, null); + } + + public static String serialize(SendTransactionParam sendTransactionParam, Map buffer) throws IOException { + String json = iconMapper.writeValueAsString(sendTransactionParam); + Map params = mapper.readValue(json, new TypeReference>() {}); + if (buffer != null) { + buffer.putAll(params); + } + return PREFIX + serializeMap(params); + } + + public static String serializeObject(Object object) { + if (object == null) { + return "\\0"; + } else if (object instanceof Map) { + // noinspection unchecked + return "{" + serializeMap((Map) object) + "}"; + } else if (object instanceof Collection) { + return "[" + serializeArray(object) + "]"; + } else if (object instanceof String) { + return escape((String) object); + } else { + throw new RuntimeException(String.format("not supported class:%s", object.getClass().getName())); + } + } + + public static String serializeMap(Map map) { + StringJoiner joiner = new StringJoiner("."); + TreeSet keys = new TreeSet<>(map.keySet()); + for (String key : keys) { + joiner.add(key); + joiner.add(serializeObject(map.get(key))); + } + return joiner.toString(); + } + + public static String serializeArray(Object arrayOrCollection) { + StringJoiner joiner = new StringJoiner("."); + if (arrayOrCollection instanceof Collection) { + Collection collection = ((Collection) arrayOrCollection); + for (Object element : collection) { + joiner.add(serializeObject(element)); + } + } else { + throw new RuntimeException(String.format("not supported class:%s", arrayOrCollection.getClass().getName())); + } + return joiner.toString(); + } + + public static String escape(String string) { + return string.replaceAll("([\\\\.{}\\[\\]])", "\\\\$1"); + } + +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/AbstractTransaction.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/AbstractTransaction.java new file mode 100644 index 00000000..a86f2f75 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/model/AbstractTransaction.java @@ -0,0 +1,76 @@ +package foundation.icon.jsonrpc.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import foundation.icon.jsonrpc.Address; + +import java.math.BigInteger; + +public abstract class AbstractTransaction { + protected BigInteger version = new BigInteger("3"); + protected Address from; + protected Address to; + @JsonInclude(JsonInclude.Include.NON_NULL) + protected BigInteger value; + protected BigInteger timestamp; + protected BigInteger nid; + @JsonInclude(JsonInclude.Include.NON_NULL) + protected BigInteger nonce; + @JsonInclude(JsonInclude.Include.NON_NULL) + protected String dataType; + @JsonInclude(JsonInclude.Include.NON_NULL) + protected Object data; + + public BigInteger getVersion() { + return version; + } + + public Address getFrom() { + return from; + } + + public Address getTo() { + return to; + } + + public BigInteger getValue() { + return value; + } + + public BigInteger getTimestamp() { + return timestamp; + } + + public BigInteger getNid() { + return nid; + } + + public BigInteger getNonce() { + return nonce; + } + + public String getDataType() { + return dataType; + } + + public Object getData() { + return data; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("AbstractTransaction{"); + sb.append("version=").append(version); + sb.append(", from=").append(from); + sb.append(", to=").append(to); + sb.append(", value=").append(value); + sb.append(", timestamp=").append(timestamp); + sb.append(", nid=").append(nid); + sb.append(", nonce=").append(nonce); + sb.append(", dataType='").append(dataType).append('\''); + sb.append(", data=").append(data); + sb.append('}'); + return sb.toString(); + } + +} + diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/CallData.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/CallData.java new file mode 100644 index 00000000..27e909a2 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/model/CallData.java @@ -0,0 +1,37 @@ +package foundation.icon.jsonrpc.model; + +import java.util.Map; +import java.util.Objects; + +public class CallData { + private String method; + private Map params; + + public CallData(String method, Map params) { + Objects.requireNonNull(method, "method required not null"); + if (method.isEmpty()) { + throw new IllegalArgumentException("method required not empty"); + } + this.method = method; + this.params = params; + } + + public String getMethod() { + return method; + } + + public Map getParams() { + return params; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("CallData{"); + sb.append("method='").append(method).append('\''); + sb.append(", params=").append(params); + sb.append('}'); + return sb.toString(); + } +} + + diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/CallParam.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/CallParam.java new file mode 100644 index 00000000..fe44e131 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/model/CallParam.java @@ -0,0 +1,52 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc.model; + +import foundation.icon.jsonrpc.Address; + +public class CallParam { + private Address to; + private String dataType = "call"; + private CallData data; + + public CallParam(Address to, CallData data) { + this.to = to; + this.data = data; + } + + public Address getTo() { + return to; + } + + public String getDataType() { + return dataType; + } + + public CallData getData() { + return data; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("CallParam{"); + sb.append("to=").append(to); + sb.append(", dataType='").append(dataType).append('\''); + sb.append(", data=").append(data); + sb.append('}'); + return sb.toString(); + } +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/DeployData.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/DeployData.java new file mode 100644 index 00000000..c3bd4aa5 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/model/DeployData.java @@ -0,0 +1,64 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc.model; + +import foundation.icon.jsonrpc.IconJsonModule; + +import java.util.Map; +import java.util.Objects; + +public class DeployData { + private String contentType; + private byte[] content; + private Map params; + + public DeployData(String contentType, byte[] content, Map params) { + Objects.requireNonNull(contentType, "contentType required not null"); + if (contentType.isEmpty()) { + throw new IllegalArgumentException("contentType required not empty"); + } + Objects.requireNonNull(content, "content required not null"); + if (content.length == 0) { + throw new IllegalArgumentException("content required not empty"); + } + this.contentType = contentType; + this.content = content; + this.params = params; + } + + public String getContentType() { + return contentType; + } + + public byte[] getContent() { + return content; + } + + public Map getParams() { + return params; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DeployData{"); + sb.append("contentType='").append(contentType).append('\''); + sb.append(", content=").append(IconJsonModule.bytesToHex(content)); + sb.append(", params=").append(params); + sb.append('}'); + return sb.toString(); + } +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/Hash.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/Hash.java new file mode 100644 index 00000000..d7544148 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/model/Hash.java @@ -0,0 +1,56 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import foundation.icon.jsonrpc.IconJsonModule; + + +public class Hash { + public static final String HEX_PREFIX = "0x"; + + private final byte[] bytes; + + public Hash(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException("bytes could not be null"); + } + this.bytes = bytes; + } + + @JsonCreator + public Hash(String string) { + if (string == null) { + throw new IllegalArgumentException("string could not be null"); + } + if (string.startsWith(HEX_PREFIX)) { + string = string.substring(2); + } + this.bytes = IconJsonModule.hexToBytes(string); + } + + public byte[] toBytes() { + return bytes; + } + + @JsonValue + @Override + public String toString() { + return HEX_PREFIX + IconJsonModule.bytesToHex(bytes); + } +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/SendTransactionParam.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/SendTransactionParam.java new file mode 100644 index 00000000..31482694 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/model/SendTransactionParam.java @@ -0,0 +1,64 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc.model; + +import foundation.icon.jsonrpc.Address; + +import java.math.BigInteger; +import java.util.Objects; + +public class SendTransactionParam extends TransactionParam { + private BigInteger stepLimit; + + public SendTransactionParam(BigInteger nid, Address to, BigInteger value, String dataType, Object data) { + super(nid, to, value, dataType, data); + Objects.requireNonNull(nid, "nid required not null"); + Objects.requireNonNull(to, "to Address required not null"); + if (value != null && value.signum() == -1) { + throw new IllegalArgumentException("nid must be positive"); + } + } + + public BigInteger getStepLimit() { + return stepLimit; + } + + public void setStepLimit(BigInteger stepLimit) { + this.stepLimit = stepLimit; + } + + public void setFrom(Address from) { + this.from = from; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("SendTransactionParam{"); + sb.append("stepLimit=").append(stepLimit); + sb.append(", version=").append(version); + sb.append(", from=").append(from); + sb.append(", to=").append(to); + sb.append(", value=").append(value); + sb.append(", timestamp=").append(timestamp); + sb.append(", nid=").append(nid); + sb.append(", nonce=").append(nonce); + sb.append(", dataType='").append(dataType).append('\''); + sb.append(", data=").append(data); + sb.append('}'); + return sb.toString(); + } +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionParam.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionParam.java new file mode 100644 index 00000000..28ae9e75 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionParam.java @@ -0,0 +1,61 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc.model; + +import foundation.icon.jsonrpc.Address; + +import java.math.BigInteger; + +public class TransactionParam extends AbstractTransaction { + public static final BigInteger TIMESTAMP_MSEC_SCALE = BigInteger.valueOf(1000); + public static BigInteger currentTimestamp() { + return TIMESTAMP_MSEC_SCALE.multiply(BigInteger.valueOf(System.currentTimeMillis())); + } + + public TransactionParam(BigInteger nid, Address to, BigInteger value, String dataType, Object data) { + super(); + this.nid = nid; + this.to = to; + this.value = value; + this.dataType = dataType; + this.data = data; + } + + public void setFrom(Address from) { + this.from = from; + } + + public void setTimestamp(BigInteger timestamp) { + this.timestamp = timestamp; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("TransactionParam{"); + sb.append("version=").append(version); + sb.append(", from=").append(from); + sb.append(", to=").append(to); + sb.append(", value=").append(value); + sb.append(", timestamp=").append(timestamp); + sb.append(", nid=").append(nid); + sb.append(", nonce=").append(nonce); + sb.append(", dataType='").append(dataType).append('\''); + sb.append(", data=").append(data); + sb.append('}'); + return sb.toString(); + } +} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionResult.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionResult.java new file mode 100644 index 00000000..c9adb3d6 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionResult.java @@ -0,0 +1,173 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.jsonrpc.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import foundation.icon.jsonrpc.Address; +import foundation.icon.jsonrpc.IconJsonModule; + +import java.math.BigInteger; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class TransactionResult { + private Address to; + private BigInteger cumulativeStepUsed; + private BigInteger stepUsed; + private BigInteger stepPrice; + private List eventLogs; + private byte[] logsBloom; + private BigInteger status; + @JsonInclude(JsonInclude.Include.NON_NULL) + private Failure failure; + @JsonInclude(JsonInclude.Include.NON_NULL) + private Address scoreAddress; + private Hash blockHash; + private BigInteger blockHeight; + private BigInteger txIndex; + private Hash txHash; + @JsonInclude(JsonInclude.Include.NON_NULL) + private Object stepUsedDetails; //[]feePayment + + public Address getTo() { + return to; + } + + public BigInteger getCumulativeStepUsed() { + return cumulativeStepUsed; + } + + public BigInteger getStepUsed() { + return stepUsed; + } + + public BigInteger getStepPrice() { + return stepPrice; + } + + public List getEventLogs() { + return eventLogs; + } + + public byte[] getLogsBloom() { + return logsBloom; + } + + public BigInteger getStatus() { + return status; + } + + public Failure getFailure() { + return failure; + } + + public Address getScoreAddress() { + return scoreAddress; + } + + public Hash getBlockHash() { + return blockHash; + } + + public BigInteger getBlockHeight() { + return blockHeight; + } + + public BigInteger getTxIndex() { + return txIndex; + } + + public Hash getTxHash() { + return txHash; + } + + public Object getStepUsedDetails() { + return stepUsedDetails; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("TransactionResult{"); + sb.append("to=").append(to); + sb.append(", cumulativeStepUsed=").append(cumulativeStepUsed); + sb.append(", stepUsed=").append(stepUsed); + sb.append(", stepPrice=").append(stepPrice); + sb.append(", eventLogs=").append(eventLogs); + sb.append(", logsBloom=").append(IconJsonModule.bytesToHex(logsBloom)); + sb.append(", status=").append(status); + sb.append(", failure=").append(failure); + sb.append(", scoreAddress=").append(scoreAddress); + sb.append(", blockHash=").append(blockHash); + sb.append(", blockHeight=").append(blockHeight); + sb.append(", txIndex=").append(txIndex); + sb.append(", txHash=").append(txHash); + sb.append(", stepUsedDetails=").append(stepUsedDetails); + sb.append('}'); + return sb.toString(); + } + + public static class EventLog { + private Address scoreAddress; + private List indexed; + private List data; + + public Address getScoreAddress() { + return scoreAddress; + } + + public List getIndexed() { + return indexed; + } + + public List getData() { + return data; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("EventLog{"); + sb.append("scoreAddress=").append(scoreAddress); + sb.append(", indexed=").append(indexed); + sb.append(", data=").append(data); + sb.append('}'); + return sb.toString(); + } + } + + public static class Failure { + private BigInteger code; + private String message; + + public BigInteger getCode() { + return code; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Failure{"); + sb.append("code=").append(code); + sb.append(", message='").append(message).append('\''); + sb.append('}'); + return sb.toString(); + } + } +} diff --git a/score-client/src/main/java/foundation/icon/score/client/DefaultScoreClient.java b/score-client/src/main/java/foundation/icon/score/client/DefaultScoreClient.java new file mode 100644 index 00000000..34593d68 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/score/client/DefaultScoreClient.java @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.score.client; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import foundation.icon.icx.KeyWallet; +import foundation.icon.icx.Wallet; +import foundation.icon.icx.crypto.KeystoreException; +import foundation.icon.jsonrpc.Address; +import foundation.icon.jsonrpc.IconJsonModule; +import foundation.icon.jsonrpc.JsonrpcClient; +import foundation.icon.jsonrpc.SendTransactionParamSerializer; +import foundation.icon.jsonrpc.model.CallData; +import foundation.icon.jsonrpc.model.CallParam; +import foundation.icon.jsonrpc.model.DeployData; +import foundation.icon.jsonrpc.model.Hash; +import foundation.icon.jsonrpc.model.SendTransactionParam; +import foundation.icon.jsonrpc.model.TransactionParam; +import foundation.icon.jsonrpc.model.TransactionResult; +import org.bouncycastle.jcajce.provider.digest.SHA3; +import org.bouncycastle.util.encoders.Base64; +import score.UserRevertedException; + +import java.io.File; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; + +public class DefaultScoreClient extends JsonrpcClient { + public static final Address ZERO_ADDRESS = new Address("cx0000000000000000000000000000000000000000"); + public static final BigInteger DEFAULT_STEP_LIMIT = new BigInteger("9502f900", 16); + public static final long BLOCK_INTERVAL = 1; + public static final long DEFAULT_RESULT_RETRY_WAIT = 0; + public static final long DEFAULT_RESULT_TIMEOUT = 10000; + + protected final BigInteger nid; + protected final Wallet wallet; + protected final Address address; + protected BigInteger stepLimit = DEFAULT_STEP_LIMIT; + protected long resultTimeout = DEFAULT_RESULT_TIMEOUT; + + public DefaultScoreClient(String url, String nid, String keyStorePath, String keyStorePassword, String address) { + this(url, nid(nid), wallet(keyStorePath, keyStorePassword), new Address(address)); + } + + public DefaultScoreClient(String url, BigInteger nid, Wallet wallet, Address address) { + super(url); + initialize(this); + + this.nid = nid; + this.wallet = wallet; + this.address = address; + } + + public DefaultScoreClient(DefaultScoreClient client) { + super(client.endpoint); + initialize(this); + + this.nid = client._nid(); + this.wallet = client._wallet(); + this.address = client._address(); + this.stepLimit = client._stepLimit(); + this.resultTimeout = client._resultTimeout(); + } + + static void initialize(JsonrpcClient client) { + client.mapper().registerModule(new IconJsonModule()); + client.mapper().setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + + public static DefaultScoreClient _deploy(String url, String nid, String keyStorePath, String keyStorePassword, String scoreFilePath, Map params) { + return _deploy(url, nid(nid), wallet(keyStorePath, keyStorePassword), scoreFilePath, params); + } + + public static DefaultScoreClient _deploy(String url, BigInteger nid, Wallet wallet, String scoreFilePath, Map params) { + JsonrpcClient client = new JsonrpcClient(url); + initialize(client); + Address address = deploy(client, nid, wallet, DEFAULT_STEP_LIMIT, ZERO_ADDRESS, scoreFilePath, params, DEFAULT_RESULT_TIMEOUT); + return new DefaultScoreClient(url, nid, wallet, address); + } + + public static Hash _deployAsync(String url, BigInteger nid, Wallet wallet, String scoreFilePath, Map params) { + JsonrpcClient client = new JsonrpcClient(url); + initialize(client); + return deployAsync(client, nid, wallet, DEFAULT_STEP_LIMIT, ZERO_ADDRESS, scoreFilePath, params); + } + + public static DefaultScoreClient getDeploymentResult(String url, BigInteger nid, Wallet wallet, Hash hash) { + JsonrpcClient client = new JsonrpcClient(url); + initialize(client); + TransactionResult txr = result(client, hash, DEFAULT_RESULT_TIMEOUT); + Address address = txr.getScoreAddress(); + return new DefaultScoreClient(url, nid, wallet, address); + } + + public void _update(String scoreFilePath, Map params) { + deploy(this, nid, wallet, DEFAULT_STEP_LIMIT, address, scoreFilePath, params, DEFAULT_RESULT_TIMEOUT); + } + + public BigInteger _nid() { + return nid; + } + + public Wallet _wallet() { + return wallet; + } + + public Address _address() { + return address; + } + + public BigInteger _stepLimit() { + return stepLimit; + } + + public void _stepLimit(BigInteger stepLimit) { + this.stepLimit = stepLimit; + } + + public long _resultTimeout() { + return resultTimeout; + } + + public void _resultTimeout(long resultTimeout) { + this.resultTimeout = resultTimeout; + } + + public T _call(Class responseType, String method, Map params) { + return call(this, responseType, address, method, params); + } + + public T _call(TypeReference responseType, String method, Map params) { + return call(this, responseType, address, method, params); + } + + public TransactionResult _send(String method, Map params) { + return send(this, nid, wallet, stepLimit, address, null, method, params, resultTimeout); + } + + public TransactionResult _send(BigInteger valueForPayable, String method, Map params) { + return send(this, nid, wallet, stepLimit, address, valueForPayable, method, params, resultTimeout); + } + + public TransactionResult _transfer(Address to, BigInteger value, String message) { + return transfer(this, nid, wallet, stepLimit, to, value, message, resultTimeout); + } + + public BigInteger _balance() { + return balance(this, address); + } + + public BigInteger _balance(Address address) { + return balance(this, address); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + static class BlockHeight { + BigInteger height; + + public BigInteger getHeight() { + return height; + } + } + + public BigInteger _lastBlockHeight() { + return lastBlock(this, BlockHeight.class).height; + } + + + public static DefaultScoreClient of(Properties properties) { + return of("", properties); + } + + public static DefaultScoreClient of(Properties properties, Map params) { + return of("", properties, params); + } + + public static DefaultScoreClient of(String prefix, Properties properties) { + return of(prefix, properties, null); + } + + public static DefaultScoreClient of(String prefix, Properties properties, Map params) { + String url = url(prefix, properties); + BigInteger nid = nid(prefix, properties); + Wallet wallet = wallet(prefix, properties); + Address address = address(prefix, properties); + String scoreFilePath = scoreFilePath(prefix, properties); + Map deployParams = params(prefix, properties, params); + if (address == null) { + System.out.printf("deploy prefix: %s, url: %s, nid: %s, keyStorePath: %s, scoreFilePath: %s, params: %s%n", + prefix, url, nid, wallet != null ? wallet.getAddress() : wallet, scoreFilePath, deployParams); + return _deploy(url, nid, wallet, scoreFilePath, deployParams); + } else { + System.out.printf("prefix: %s, url: %s, nid: %s, wallet: %s, address: %s%n", + prefix, url, nid, wallet != null ? wallet.getAddress() : wallet, address); + DefaultScoreClient client = new DefaultScoreClient(url, nid, wallet, address); + if (isUpdate(prefix, properties) && scoreFilePath != null && !scoreFilePath.isEmpty()) { + System.out.printf("update scoreFilePath: %s, params: %s%n", scoreFilePath, deployParams); + client._update(scoreFilePath, deployParams); + } + return client; + } + } + + public static String url(Properties properties) { + return url("", properties); + } + + public static String url(String prefix, Properties properties) { + return properties.getProperty(prefix+"url"); + } + + public static BigInteger nid(Properties properties) { + return nid("", properties); + } + + public static BigInteger nid(String prefix, Properties properties) { + return nid(properties.getProperty(prefix+"nid")); + } + + public static BigInteger nid(String nid) { + if (nid.startsWith("0x")) { + return new BigInteger(nid.substring(2), 16); + } else { + return new BigInteger(nid); + } + } + + public static Wallet wallet(Properties properties) { + return wallet("", properties); + } + + public static Wallet wallet(String prefix, Properties properties) { + String keyStore = properties.getProperty(prefix+"keyStore"); + if (keyStore == null || keyStore.isEmpty()) { + return null; + } + String keyPassword = properties.getProperty(prefix+"keyPassword"); + if (keyPassword == null || keyPassword.isEmpty()) { + String keySecret = properties.getProperty(prefix+"keySecret"); + try { + System.out.println("using keySecret "+keySecret); + keyPassword = Files.readString(Path.of(keySecret)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return wallet(keyStore, keyPassword); + } + + public static Wallet wallet(String keyStorePath, String keyStorePassword) { + try { + System.out.println("load wallet "+keyStorePath); + return KeyWallet.load(keyStorePassword, new File(keyStorePath)); + } catch (IOException | KeystoreException e) { + throw new RuntimeException(e); + } + } + + public static Address address(Properties properties) { + return address("", properties); + } + + public static Address address(String prefix, Properties properties) { + String address = properties.getProperty(prefix+"address"); + if (address == null || address.isEmpty()) { + return null; + } + return address(address); + } + + public static Address address(String address) { + return new Address(address); + } + + public static boolean isUpdate(Properties properties) { + return isUpdate("", properties); + } + + public static boolean isUpdate(String prefix, Properties properties) { + return Boolean.parseBoolean( + (String)properties.getOrDefault(prefix+"isUpdate", + Boolean.FALSE.toString())); + } + + public static String scoreFilePath(Properties properties) { + return scoreFilePath("", properties); + } + + public static String scoreFilePath(String prefix, Properties properties) { + return properties.getProperty(prefix+"scoreFilePath"); + } + + public static Map params(Properties properties) { + return params("", properties); + } + + public static Map params(String prefix, Properties properties) { + return params(prefix, properties, null); + } + + public static Map params(String prefix, Properties properties, Map overwrite) { + String paramsKey = prefix+"params."; + Map params = new HashMap<>(); + for(Map.Entry entry : properties.entrySet()) { + String key = ((String)entry.getKey()); + if (key.startsWith(paramsKey)) { + params.put(key.substring(paramsKey.length()), entry.getValue()); + } + } + if (overwrite != null) { + for(Map.Entry entry : overwrite.entrySet()) { + params.put(entry.getKey(), entry.getValue()); + } + } + return params.isEmpty() ? null : params; + } + + + public static CallData callData(String method, Map params) { + return new CallData(method, params != null && !params.isEmpty() ? params : null); + } + + public static T call( + JsonrpcClient client, Class responseType, Address address, + String method, Map params) { + return client.request(responseType, "icx_call", new CallParam(address, callData(method, params))); + } + + public static T call( + JsonrpcClient client, TypeReference responseType, Address address, + String method, Map params) { + return client.request(responseType, "icx_call", new CallParam(address, callData(method, params))); + } + + static Hash sendTransaction(JsonrpcClient client, Wallet wallet, SendTransactionParam sendTransactionParam) { + Objects.requireNonNull(client, "client required not null"); + Objects.requireNonNull(wallet, "wallet required not null"); + Objects.requireNonNull(wallet, "sendTransactionParam required not null"); + + sendTransactionParam.setFrom(Address.of(wallet)); + if (sendTransactionParam.getTimestamp() == null) { + sendTransactionParam.setTimestamp(TransactionParam.currentTimestamp()); + } + if (sendTransactionParam.getStepLimit() == null) { + sendTransactionParam.setStepLimit(DEFAULT_STEP_LIMIT); + } + if (sendTransactionParam.getNid() == null) { + throw new IllegalArgumentException("nid could not be null"); + } + + Map params = new HashMap<>(); + String serialized; + try { + serialized = SendTransactionParamSerializer.serialize(sendTransactionParam, params); + } catch (IOException e) { + throw new RuntimeException(e); + } + byte[] digest = new SHA3.Digest256().digest(serialized.getBytes(StandardCharsets.UTF_8)); + String signature = Base64.toBase64String(wallet.sign(digest)); + params.put("signature", signature); + return client.request(Hash.class, "icx_sendTransaction", params); + } + + static void waitBlockInterval() { + // System.out.printf("wait block interval %d msec%n", BLOCK_INTERVAL); + // try { + // Thread.sleep(BLOCK_INTERVAL); + // } catch (InterruptedException ie) { + // ie.printStackTrace(); + // } + } + + public static TransactionResult send( + JsonrpcClient client, BigInteger nid, Wallet wallet, BigInteger stepLimit, Address address, + BigInteger valueForPayable, String method, Map params, + long timeout) { + SendTransactionParam tx = new SendTransactionParam(nid, address, valueForPayable, "call", callData(method, params)); + Hash txh = sendTransaction(client, wallet, tx); + waitBlockInterval(); + System.out.println("tx hash is: "+txh); + return result(client, txh, timeout); + } + + public static Address deploy( + JsonrpcClient client, BigInteger nid, Wallet wallet, BigInteger stepLimit, Address address, + String scoreFilePath, Map params, + long timeout) { + + byte[] content; + try { + content = Files.readAllBytes(Path.of(scoreFilePath)); + } catch (IOException e) { + throw new RuntimeException(e); + } + String contentType; + if (scoreFilePath.endsWith(".jar")) { + contentType = "application/java"; + } else if (scoreFilePath.endsWith(".zip")) { + contentType = "application/zip"; + } else { + throw new RuntimeException("not supported score file"); + } + SendTransactionParam tx = new SendTransactionParam(nid, address,null,"deploy", new DeployData(contentType, content, params)); + Hash txh = sendTransaction(client, wallet, tx); + waitBlockInterval(); + TransactionResult txr = result(client, txh, timeout); + System.out.println("SCORE address: "+txr.getScoreAddress()); + return txr.getScoreAddress(); + } + + public static Hash deployAsync( + JsonrpcClient client, BigInteger nid, Wallet wallet, BigInteger stepLimit, Address address, + String scoreFilePath, Map params) { + byte[] content; + try { + content = Files.readAllBytes(Path.of(scoreFilePath)); + } catch (IOException e) { + throw new RuntimeException(e); + } + String contentType; + if (scoreFilePath.endsWith(".jar")) { + contentType = "application/java"; + } else if (scoreFilePath.endsWith(".zip")) { + contentType = "application/zip"; + } else { + throw new RuntimeException("not supported score file"); + } + + SendTransactionParam tx = new SendTransactionParam(nid, address,null,"deploy", new DeployData(contentType, content, params)); + return sendTransaction(client, wallet, tx); + } + + public static TransactionResult transfer( + JsonrpcClient client, BigInteger nid, Wallet wallet, BigInteger stepLimit, Address address, + BigInteger value, String message, long timeout) { + SendTransactionParam tx; + if (message != null) { + tx = new SendTransactionParam(nid, address, value, "message", message.getBytes(StandardCharsets.UTF_8)); + } else { + tx = new SendTransactionParam(nid, address, value, null, null); + } + Hash txh = sendTransaction(client, wallet, tx); + waitBlockInterval(); + return result(client, txh, timeout); + } + + public static TransactionResult result(JsonrpcClient client, Hash txh, long timeout) { + Map params = Map.of("txHash", txh); + long etime = System.currentTimeMillis() + timeout; + TransactionResult txr = null; + while(txr == null) { + try { + txr = client.request(TransactionResult.class, "icx_getTransactionResult", params); + } catch (JsonrpcError e) { + if (e.getCode() == -31002 /* pending */ + || e.getCode() == -31003 /* executing */ + || e.getCode() == -31004 /* not found */) { + if (timeout > 0 && System.currentTimeMillis() >= etime) { + throw new RuntimeException("timeout"); + } + } else { + throw new RuntimeException(e); + } + } + } + if (!BigInteger.ONE.equals(txr.getStatus())) { + TransactionResult.Failure failure = txr.getFailure(); + int revertCode = failure.getCode().intValue(); + String revertMessage = failure.getMessage(); + if (revertCode >= 32) { + throw new UserRevertedException(revertCode - 32, revertMessage); + } else { + throw new RevertedException(revertCode, revertMessage); + } + } + return txr; + } + + public static BigInteger balance(JsonrpcClient client, Address address) { + return client.request(BigInteger.class, "icx_getBalance", Map.of("address", address)); + } + + public static T lastBlock(JsonrpcClient client, Class blockType) { + return client.request(blockType, "icx_getLastBlock", null); + } + +} diff --git a/score-client/src/main/java/foundation/icon/score/client/RevertedException.java b/score-client/src/main/java/foundation/icon/score/client/RevertedException.java new file mode 100644 index 00000000..b6af28d5 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/score/client/RevertedException.java @@ -0,0 +1,29 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.score.client; + +public class RevertedException extends score.RevertedException { + private int code; + public RevertedException(int code, String message) { + super(message); + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/score-client/src/main/java/foundation/icon/score/client/ScoreClient.java b/score-client/src/main/java/foundation/icon/score/client/ScoreClient.java new file mode 100644 index 00000000..7ab6d42b --- /dev/null +++ b/score-client/src/main/java/foundation/icon/score/client/ScoreClient.java @@ -0,0 +1,28 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.score.client; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.SOURCE) +public @interface ScoreClient { + String suffix() default "ScoreClient"; +} diff --git a/score-client/src/main/java/foundation/icon/score/client/ScoreClientProcessor.java b/score-client/src/main/java/foundation/icon/score/client/ScoreClientProcessor.java new file mode 100644 index 00000000..d185410b --- /dev/null +++ b/score-client/src/main/java/foundation/icon/score/client/ScoreClientProcessor.java @@ -0,0 +1,425 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.score.client; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import foundation.icon.annotation_processor.AbstractProcessor; +import foundation.icon.annotation_processor.ProcessorUtil; +import foundation.icon.icx.Wallet; +import foundation.icon.jsonrpc.Address; +import foundation.icon.jsonrpc.model.TransactionResult; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Payable; + +import javax.annotation.processing.Filer; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.function.Consumer; + +public class ScoreClientProcessor extends AbstractProcessor { + static final String METHOD_OF = "_of"; + static final String PARAM_PROPERTEIS = "properties"; + static final String PARAM_PREFIX = "prefix"; + static final String METHOD_DEPLOY = "_deploy"; + static final String PARAM_URL = "url"; + static final String PARAM_NID = "nid"; + static final String PARAM_WALLET = "wallet"; + static final String PARAM_ADDRESS = "address"; + static final String PARAM_CLIENT = "client"; + static final String PARAM_SCORE_FILE_PATH = "scoreFilePath"; + static final String PARAM_PARAMS = "params"; + // + static final String PARAM_PAYABLE_VALUE = "valueForPayable"; + static final String PARAM_CONSUMER = "consumerFunc"; + static final String PARAM_STEP_LIMIT = "stepLimit"; + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + } + + @Override + public Set getSupportedAnnotationTypes() { + Set s = new HashSet<>(); + s.add(ScoreClient.class.getCanonicalName()); + return s; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + boolean ret = false; + for (TypeElement annotation : annotations) { + Set annotationElements = roundEnv.getElementsAnnotatedWith(annotation); + for (Element element : annotationElements) { + if (element.getKind().isInterface() || element.getKind().isClass() || element.getKind().isField()) { + messager.noteMessage("process %s %s", element.getKind(), element.asType(), element.getSimpleName()); + generateImplementClass(processingEnv.getFiler(), element); + ret = true; + } else { + throw new RuntimeException("not support"); + } + } + } + return ret; + } + + private void generateImplementClass(Filer filer, Element element) { + TypeElement typeElement; + if (element instanceof TypeElement) { + typeElement = (TypeElement) element; + } else if (element instanceof VariableElement) { + typeElement = super.getTypeElement(element.asType()); + } else { + throw new RuntimeException("not support"); + } + + ClassName elementClassName = ClassName.get(typeElement); + ScoreClient ann = element.getAnnotation(ScoreClient.class); + ClassName className = ClassName.get(elementClassName.packageName(), elementClassName.simpleName() + ann.suffix()); + TypeSpec typeSpec = typeSpec(className, typeElement); + JavaFile javaFile = JavaFile.builder(className.packageName(), typeSpec).build(); + try { + javaFile.writeTo(filer); + } catch (IOException e) { + messager.warningMessage("create javaFile error : %s", e.getMessage()); + } + } + + private TypeSpec typeSpec(ClassName className, TypeElement element) { + TypeSpec.Builder builder = TypeSpec + .classBuilder(className) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .superclass(DefaultScoreClient.class) + .addSuperinterfaces(ProcessorUtil.getSuperinterfaces(element)); + + if (element.getKind().isInterface()) { + builder.addSuperinterface(element.asType()); + builder.addMethod(deployMethodSpec(className, null)); + } + + //Constructor + builder.addMethod(MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(ParameterSpec.builder(String.class, PARAM_URL).build()) + .addParameter(ParameterSpec.builder(BigInteger.class, PARAM_NID).build()) + .addParameter(ParameterSpec.builder(Wallet.class, PARAM_WALLET).build()) + .addParameter(ParameterSpec.builder(Address.class, PARAM_ADDRESS).build()) + .addStatement("super($L, $L, $L, $L)", + PARAM_URL, PARAM_NID, PARAM_WALLET, PARAM_ADDRESS).build()); + builder.addMethod(MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(ParameterSpec.builder(DefaultScoreClient.class, PARAM_CLIENT).build()) + .addStatement("super($L)", PARAM_CLIENT).build()); + + //_of(Properties) + builder.addMethod(MethodSpec.methodBuilder(METHOD_OF) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addParameter(ParameterSpec.builder(Properties.class, PARAM_PROPERTEIS).build()) + .addStatement("return _of(\"\", $L)", PARAM_PROPERTEIS) + .returns(className) + .build()); + //_of(String prefix, Properties) + builder.addMethod(MethodSpec.methodBuilder(METHOD_OF) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addParameter(ParameterSpec.builder(String.class, PARAM_PREFIX).build()) + .addParameter(ParameterSpec.builder(Properties.class, PARAM_PROPERTEIS).build()) + .addStatement("return new $T($T.of($L, $L))", className, DefaultScoreClient.class, PARAM_PREFIX, PARAM_PROPERTEIS) + .returns(className) + .build()); + + builder.addMethods(overrideMethods(element)); + builder.addMethods(deployMethods(className, element)); + return builder.build(); + } + + private List overrideMethods(TypeElement element) { + List methods = new ArrayList<>(); + TypeMirror superClass = element.getSuperclass(); + if (!superClass.getKind().equals(TypeKind.NONE) && !superClass.toString().equals(Object.class.getName())) { + messager.noteMessage("superClass[kind:%s, name:%s]", superClass.getKind().name(), superClass.toString()); + List superMethods = overrideMethods(super.getTypeElement(element.getSuperclass())); + methods.addAll(superMethods); + } + + for (TypeMirror inf : element.getInterfaces()) { + TypeElement infElement = super.getTypeElement(inf); + List infMethods = overrideMethods(infElement); + methods.addAll(infMethods); + } + + boolean mustGenerate = element.getKind().isInterface(); + for (Element enclosedElement : element.getEnclosedElements()) { + if (ElementKind.METHOD.equals(enclosedElement.getKind()) && + ProcessorUtil.hasModifier(enclosedElement, Modifier.PUBLIC) && + !ProcessorUtil.hasModifier(enclosedElement, Modifier.STATIC)) { + ExecutableElement ee = (ExecutableElement) enclosedElement; + External external = ee.getAnnotation(External.class); + + if (external != null || mustGenerate) { + CodeBlock paramsCodeblock = paramsCodeblock(ee); + MethodSpec methodSpec = methodSpec(ee, paramsCodeblock); + addMethod(methods, methodSpec, element); + boolean isExternal = external != null ? + !external.readonly() : + methodSpec.returnType.equals(TypeName.VOID); + if (isExternal) { + addMethod(methods, consumerMethodSpec(methodSpec, paramsCodeblock, false), element); + if (ee.getAnnotation(Payable.class) != null) { + addMethod(methods, payableMethodSpec(methodSpec, paramsCodeblock), element); + addMethod(methods, consumerMethodSpec(methodSpec, paramsCodeblock, true), element); + } + } + } + } + } + return methods; + } + + private void addMethod(List methods, MethodSpec methodSpec, TypeElement element) { + if (methodSpec != null) { + MethodSpec conflictMethod = ProcessorUtil.getConflictMethod(methods, methodSpec); + if (conflictMethod != null) { + methods.remove(conflictMethod); + if (element.getKind().isInterface()) { + messager.warningMessage( + "Redeclare '%s %s(%s)' in %s", + conflictMethod.returnType.toString(), + conflictMethod.name, + ProcessorUtil.parameterSpecToString(conflictMethod.parameters), + element.getQualifiedName()); + } + } + methods.add(methodSpec); + } + } + + private CodeBlock paramsCodeblock(ExecutableElement element) { + if (element == null || element.getParameters() == null || element.getParameters().size() == 0) { + return null; + } + CodeBlock.Builder builder = CodeBlock.builder(); + builder.addStatement("$T<$T,$T> $L = new $T<>()", + Map.class, String.class, Object.class, PARAM_PARAMS, HashMap.class); + for (VariableElement ve : element.getParameters()) { + ParameterSpec ps = ParameterSpec.get(ve); + builder.addStatement("$L.put(\"$L\",$L)", PARAM_PARAMS, ps.name, ps.name); + } + return builder.build(); + } + + static Map wrapperTypeNames = Map.of( + TypeKind.BOOLEAN, TypeName.get(Boolean.class), + TypeKind.BYTE, TypeName.get(Boolean.class), + TypeKind.SHORT, TypeName.get(Byte.class), + TypeKind.INT, TypeName.get(Integer.class), + TypeKind.LONG, TypeName.get(Long.class), + TypeKind.CHAR, TypeName.get(Character.class), + TypeKind.FLOAT, TypeName.get(Float.class), + TypeKind.DOUBLE, TypeName.get(Double.class)); + + private MethodSpec methodSpec(ExecutableElement ee, CodeBlock paramsCodeblock) { + if (ee.getAnnotation(EventLog.class) != null) { + return notSupportedMethod(ee, "not supported EventLog method", null); + } + + String methodName = ee.getSimpleName().toString(); + TypeMirror returnType = ee.getReturnType(); + TypeName returnTypeName = TypeName.get(returnType); + External external = ee.getAnnotation(External.class); + + MethodSpec.Builder builder = MethodSpec + .methodBuilder(methodName) + .addModifiers(ProcessorUtil.getModifiers(ee, Modifier.ABSTRACT)) + .addParameters(ProcessorUtil.getParameterSpecs(ee)) + .returns(returnTypeName); +// .addAnnotation(Override.class); + + String params = "null"; + if (paramsCodeblock != null) { + builder.addCode(paramsCodeblock); + params = PARAM_PARAMS; + } + + boolean isVoid = returnTypeName.equals(TypeName.VOID); + boolean isExternal = external != null ? !external.readonly() : isVoid; + if (isExternal) { + if (isVoid) { + builder.addStatement("super._send(\"$L\", $L)", methodName, params); + if (ee.getAnnotation(Payable.class) != null) { + builder.addJavadoc("To payable, use $L($T $L, ...)", methodName, BigInteger.class, PARAM_PAYABLE_VALUE); + } + } else { + return notSupportedMethod(ee, "not supported response of writable method in ScoreClient", + CodeBlock.builder().add("$L($T<$T> $L, ...)", + methodName, Consumer.class, TransactionResult.class, PARAM_CONSUMER).build()); + } + } else { + if (!isVoid) { + if (returnType.getKind().isPrimitive()) { + builder.addStatement("return super._call($T.class, \"$L\", $L)", + wrapperTypeNames.get(returnType.getKind()), methodName, params); + } else { + if (returnType.getKind().equals(TypeKind.DECLARED) && + ((DeclaredType)returnType).getTypeArguments().size() > 0) { + builder.addStatement("return super._call(new $T<$T>(){}, \"$L\", $L)", + TypeReference.class, returnTypeName, methodName, params); + } else { + builder.addStatement("return super._call($T.class, \"$L\", $L)", + returnTypeName, methodName, params); + } + } + } else { + return notSupportedMethod(ee, "not supported, void of readonly method in ScoreClient", null); + } + } + return builder.build(); + } + + private MethodSpec payableMethodSpec(MethodSpec methodSpec, CodeBlock paramsCodeblock) { + MethodSpec.Builder builder = MethodSpec.methodBuilder(methodSpec.name) + .addModifiers(methodSpec.modifiers) + .addParameter(BigInteger.class, PARAM_PAYABLE_VALUE) + .addParameters(methodSpec.parameters) + .returns(TypeName.VOID); + + String params = "null"; + if (paramsCodeblock != null) { + builder.addCode(paramsCodeblock); + params = PARAM_PARAMS; + } + builder.addStatement("super._send($L, \"$L\", $L)", PARAM_PAYABLE_VALUE, methodSpec.name, params); + return builder.build(); + } + + private MethodSpec consumerMethodSpec(MethodSpec methodSpec, CodeBlock paramsCodeblock, boolean isPayable) { + MethodSpec.Builder builder = MethodSpec.methodBuilder(methodSpec.name) + .addModifiers(methodSpec.modifiers) + .addParameter(ParameterSpec.builder( + ParameterizedTypeName.get(Consumer.class, TransactionResult.class), PARAM_CONSUMER).build()) + .returns(TypeName.VOID); + + String params = "null"; + if (paramsCodeblock != null) { + builder.addCode(paramsCodeblock); + params = PARAM_PARAMS; + } + if (isPayable) { + builder.addParameter(BigInteger.class, PARAM_PAYABLE_VALUE) + .addStatement("$L.accept(super._send($L, \"$L\", $L))", + PARAM_CONSUMER, PARAM_PAYABLE_VALUE, methodSpec.name, params); + } else { + builder.addStatement("$L.accept(super._send(\"$L\", $L))", PARAM_CONSUMER, methodSpec.name, params); + } + return builder.addParameters(methodSpec.parameters).build(); + } + + private MethodSpec notSupportedMethod(ExecutableElement ee, String msg, CodeBlock instead) { + String methodName = ee.getSimpleName().toString(); + TypeName returnTypeName = TypeName.get(ee.getReturnType()); + return MethodSpec.methodBuilder(methodName) + .addModifiers(ProcessorUtil.getModifiers(ee, Modifier.ABSTRACT)) + .addParameters(ProcessorUtil.getParameterSpecs(ee)) + .returns(returnTypeName) + .addStatement("throw new $T(\"$L\")", RuntimeException.class, msg) + .addJavadoc("@deprecated Do not use this method, this is generated only for preventing compile error.\n Instead, use $L\n", + instead != null ? instead : "N/A") + .addJavadoc("@throws $L(\"$L\")", RuntimeException.class.getName(), msg) + .addAnnotation(Deprecated.class) + .build(); + } + + private List deployMethods(ClassName className, TypeElement element) { + List methods = new ArrayList<>(); + TypeMirror superClass = element.getSuperclass(); + if (!superClass.getKind().equals(TypeKind.NONE) && !superClass.toString().equals(Object.class.getName())) { + messager.noteMessage("superClass[kind:%s, name:%s]", superClass.getKind().name(), superClass.toString()); + List superMethods = deployMethods(className, super.getTypeElement(element.getSuperclass())); + methods.addAll(superMethods); + } + + for (Element enclosedElement : element.getEnclosedElements()) { + if (ElementKind.CONSTRUCTOR.equals(enclosedElement.getKind()) && + ProcessorUtil.hasModifier(enclosedElement, Modifier.PUBLIC)) { + methods.add(deployMethodSpec(className, (ExecutableElement) enclosedElement)); + } + } + return methods; + } + + private MethodSpec deployMethodSpec(ClassName className, ExecutableElement element) { + MethodSpec.Builder builder = MethodSpec.methodBuilder(METHOD_DEPLOY) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addParameter(ParameterSpec.builder(String.class, PARAM_URL).build()) + .addParameter(ParameterSpec.builder(BigInteger.class, PARAM_NID).build()) + .addParameter(ParameterSpec.builder(Wallet.class, PARAM_WALLET).build()) + .addParameter(ParameterSpec.builder(String.class, PARAM_SCORE_FILE_PATH).build()) + .returns(className); + + if (element != null) { + builder.addParameters(ProcessorUtil.getParameterSpecs(element)); + } else { + builder.addParameter(ParameterSpec.builder( + ParameterizedTypeName.get(Map.class, String.class, Object.class), PARAM_PARAMS).build()); + } + + CodeBlock paramsCodeblock = paramsCodeblock(element); + if (paramsCodeblock != null) { + builder.addCode(paramsCodeblock); + } + builder + .addStatement("return new $T($T._deploy($L,$L,$L,$L,$L))", + className, DefaultScoreClient.class, + PARAM_URL, PARAM_NID, PARAM_WALLET, PARAM_SCORE_FILE_PATH, + paramsCodeblock != null || element == null ? PARAM_PARAMS : "null") + .build(); + return builder.build(); + } + +} diff --git a/score-client/src/main/java/foundation/icon/score/client/ScoreInterface.java b/score-client/src/main/java/foundation/icon/score/client/ScoreInterface.java new file mode 100644 index 00000000..7bfa3b1a --- /dev/null +++ b/score-client/src/main/java/foundation/icon/score/client/ScoreInterface.java @@ -0,0 +1,29 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.score.client; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.SOURCE) +public @interface ScoreInterface { + String suffix() default "ScoreInterface"; + String addressGetter() default "_address"; +} diff --git a/score-client/src/main/java/foundation/icon/score/client/ScoreInterfaceProcessor.java b/score-client/src/main/java/foundation/icon/score/client/ScoreInterfaceProcessor.java new file mode 100644 index 00000000..70aa69c2 --- /dev/null +++ b/score-client/src/main/java/foundation/icon/score/client/ScoreInterfaceProcessor.java @@ -0,0 +1,282 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package foundation.icon.score.client; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import foundation.icon.annotation_processor.AbstractProcessor; +import foundation.icon.annotation_processor.ProcessorUtil; +import score.Address; +import score.Context; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Payable; + +import javax.annotation.processing.Filer; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.StringJoiner; + +/* + * TODO generate exception each Method + * GenericPredefinedException + * - Status.OutOfStep + * - Status.StackOverflow + * handle IllegalArgumentException + * - Status.ContractNotFound + * - Status.MethodNotFound + * - Status.MethodNotPayable + * - Status.InvalidParameter + * - Status.OutOfBalance + * - Status.PackageError + * handle RevertedException + * - Status.UnknownFailure + * - s < Status.UserReversionStart + * handle UserRevertedException + * - Status.UserReversionStart <= s < Status.UserReversionEnd + * + * Exception extends score.UserRevertException + * Exception extends Exception + */ +public class ScoreInterfaceProcessor extends AbstractProcessor { + static final String MEMBER_ADDRESS = "address"; + static final String PARAM_PAYABLE_VALUE = "valueForPayable"; + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + } + + @Override + public Set getSupportedAnnotationTypes() { + Set s = new HashSet<>(); + s.add(ScoreInterface.class.getCanonicalName()); + return s; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + boolean ret = false; + for (TypeElement annotation : annotations) { + Set annotationElements = roundEnv.getElementsAnnotatedWith(annotation); + for (Element element : annotationElements) { + if (element.getKind().isInterface() || element.getKind().isClass()) { + messager.noteMessage("process %s %s", element.getKind(), element.asType(), element.getSimpleName()); + generateImplementClass(processingEnv.getFiler(), (TypeElement) element); + ret = true; + } else { + throw new RuntimeException("not support"); + } + } + } + return ret; + } + + private void generateImplementClass(Filer filer, TypeElement element) { + ClassName interfaceClassName = ClassName.get(element); + TypeSpec typeSpec = typeSpec(element); + JavaFile javaFile = JavaFile.builder(interfaceClassName.packageName(), typeSpec).build(); + try { + javaFile.writeTo(filer); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private TypeSpec typeSpec(TypeElement element) { + ClassName interfaceClassName = ClassName.get(element); + ScoreInterface scoreInterface = element.getAnnotation(ScoreInterface.class); + ClassName className = ClassName.get(interfaceClassName.packageName(), interfaceClassName.simpleName() + scoreInterface.suffix()); + TypeSpec.Builder builder = TypeSpec + .classBuilder(ClassName.get(interfaceClassName.packageName(), className.simpleName())) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL); + + if (element.getKind().isInterface()) { + builder.addSuperinterface(element.asType()); + } + + //Fields + builder.addField(Address.class, MEMBER_ADDRESS, Modifier.PROTECTED, Modifier.FINAL); + + //Constructor + builder.addMethod(MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(ParameterSpec.builder(Address.class, MEMBER_ADDRESS).build()) + .addStatement("this.$L = $L", MEMBER_ADDRESS, MEMBER_ADDRESS).build()); + + //addressGetter + builder.addMethod(MethodSpec.methodBuilder(scoreInterface.addressGetter()) + .addModifiers(Modifier.PUBLIC) + .returns(Address.class) + .addStatement("return this.$L", MEMBER_ADDRESS).build()); + + List methods = overrideMethods(element); + builder.addMethods(methods); + return builder.build(); + } + + private List overrideMethods(TypeElement element) { + List methods = new ArrayList<>(); + TypeMirror superClass = element.getSuperclass(); + if (!superClass.getKind().equals(TypeKind.NONE) && !superClass.toString().equals(Object.class.getName())) { + messager.noteMessage("superClass[kind:%s, name:%s]", superClass.getKind().name(), superClass.toString()); + List superMethods = overrideMethods(super.getTypeElement(element.getSuperclass())); + methods.addAll(superMethods); + } + + for (TypeMirror inf : element.getInterfaces()) { + TypeElement infElement = super.getTypeElement(inf); + List infMethods = overrideMethods(infElement); + methods.addAll(infMethods); + } + + boolean mustGenerate = element.getKind().isInterface(); + for (Element enclosedElement : element.getEnclosedElements()) { + if (ElementKind.METHOD.equals(enclosedElement.getKind()) && + ProcessorUtil.hasModifier(enclosedElement, Modifier.PUBLIC) && + !ProcessorUtil.hasModifier(enclosedElement, Modifier.STATIC)) { + ExecutableElement ee = (ExecutableElement) enclosedElement; + External external = ee.getAnnotation(External.class); + if (external != null || mustGenerate) { + MethodSpec methodSpec = methodSpec(ee, mustGenerate); + addMethod(methods, methodSpec, element); + if (external != null && !external.readonly() && ee.getAnnotation(Payable.class) != null) { + addMethod(methods, payableMethodSpec(ee, methodSpec), element); + } + } + } + } + return methods; + } + + private void addMethod(List methods, MethodSpec methodSpec, TypeElement element) { + if (methodSpec != null) { + MethodSpec conflictMethod = ProcessorUtil.getConflictMethod(methods, methodSpec); + if (conflictMethod != null) { + methods.remove(conflictMethod); + messager.warningMessage( + "Redeclare '%s %s(%s)' in %s", + conflictMethod.returnType.toString(), + conflictMethod.name, + ProcessorUtil.parameterSpecToString(conflictMethod.parameters), + element.getQualifiedName()); + } + methods.add(methodSpec); + } + } + + private String callParameters(ExecutableElement element) { + StringJoiner variables = new StringJoiner(", "); + variables.add(String.format("this.%s", MEMBER_ADDRESS)); + variables.add(String.format("\"%s\"", element.getSimpleName().toString())); + for (VariableElement variableElement : element.getParameters()) { + variables.add(variableElement.getSimpleName().toString()); + } + return variables.toString(); + } + + private MethodSpec methodSpec(ExecutableElement ee, boolean mustGenerate) { + if (ee.getAnnotation(EventLog.class) != null) { + return notSupportedMethod(ee, "not supported EventLog method"); + } + + String methodName = ee.getSimpleName().toString(); + TypeMirror returnType = ee.getReturnType(); + TypeName returnTypeName = TypeName.get(returnType); + + MethodSpec.Builder builder = MethodSpec + .methodBuilder(methodName) +// .addAnnotation(Override.class) + .addModifiers(ProcessorUtil.getModifiers(ee, Modifier.ABSTRACT)) + .addParameters(ProcessorUtil.getParameterSpecs(ee)) + .returns(returnTypeName); + + String callParameters = callParameters(ee); + if (returnTypeName.equals(TypeName.VOID)) { + builder.addStatement("$T.call($L)", Context.class, callParameters); + } else { + if (returnType.getKind().equals(TypeKind.DECLARED) && + ((DeclaredType)returnType).getTypeArguments().size() > 0) { + builder.addStatement("return ($T)$T.call($L)", returnTypeName, Context.class, callParameters); + } else { + builder.addStatement("return $T.call($T.class, $L)", Context.class, returnTypeName, callParameters); + } + } + return builder.build(); + } + + private MethodSpec payableMethodSpec(ExecutableElement ee, MethodSpec methodSpec) { + MethodSpec.Builder builder = MethodSpec.methodBuilder(methodSpec.name) + .addModifiers(methodSpec.modifiers) + .addParameter(BigInteger.class, PARAM_PAYABLE_VALUE) + .addParameters(methodSpec.parameters) + .returns(methodSpec.returnType); + + String callParameters = callParameters(ee); + TypeMirror returnType = ee.getReturnType(); + if (methodSpec.returnType.equals(TypeName.VOID)) { + builder.addStatement("$T.call($L, $L)", Context.class, PARAM_PAYABLE_VALUE, callParameters); + } else { + if (returnType.getKind().equals(TypeKind.DECLARED) && + ((DeclaredType)returnType).getTypeArguments().size() > 0) { + builder.addStatement("return ($T)$T.call($L, $L)", methodSpec.returnType, Context.class, PARAM_PAYABLE_VALUE, callParameters); + } else { + builder.addStatement("return $T.call($T.class, $L, $L)", Context.class, methodSpec.returnType, PARAM_PAYABLE_VALUE, callParameters); + } + } + return builder.build(); + } + + private MethodSpec notSupportedMethod(ExecutableElement ee, String msg) { + String methodName = ee.getSimpleName().toString(); + TypeName returnTypeName = TypeName.get(ee.getReturnType()); + return MethodSpec.methodBuilder(methodName) + .addModifiers(ProcessorUtil.getModifiers(ee, Modifier.ABSTRACT)) + .addParameters(ProcessorUtil.getParameterSpecs(ee)) + .returns(returnTypeName) + .addStatement("throw new $T(\"$L\")", RuntimeException.class, msg) + .addJavadoc("@deprecated Do not use this method, this is generated only for preventing compile error. $L\n", msg) + .addJavadoc("@throws $L", RuntimeException.class.getName()) + .addAnnotation(Deprecated.class) + .build(); + } +} diff --git a/score-lib/build.gradle b/score-lib/build.gradle new file mode 100644 index 00000000..28f2129d --- /dev/null +++ b/score-lib/build.gradle @@ -0,0 +1,34 @@ +plugins { + id 'java' +} + +version '0.1.0' + +repositories { + mavenCentral() +} + +optimizedJar.enabled = false + +dependencies { + compileOnly 'foundation.icon:javaee-api:0.9.1' + implementation 'foundation.icon:javaee-scorex:0.5.2' + implementation 'com.github.sink772:minimal-json:0.9.7' + + compileOnly 'foundation.icon:javaee-score-client:0.9.0' + annotationProcessor 'foundation.icon:javaee-score-client:0.9.0' +// + implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3' + implementation 'foundation.icon:icon-sdk:2.1.0' +// +// + testImplementation 'foundation.icon:javaee-unittest:0.9.4' + testImplementation "org.junit.jupiter:junit-jupiter:5.8.2" + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation 'org.mockito:mockito-core:4.5.1' + testRuntimeOnly 'org.mockito:mockito-inline:4.5.1' +} + +test { + useJUnitPlatform() +} diff --git a/settings.gradle b/settings.gradle index 4627c80f..1e359454 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,12 @@ rootProject.name = 'cps_java_contracts' -include ('CPFTreasury', -'CPSTreasury') + +include (':CPFTreasury') + +include (':CPSTreasury') +project(':CPSTreasury').projectDir = file("CPSTreasury") + +include ('score-client') + +include ('test-lib') + +include ('score-lib') diff --git a/test-lib/build.gradle b/test-lib/build.gradle new file mode 100644 index 00000000..bb9b7c53 --- /dev/null +++ b/test-lib/build.gradle @@ -0,0 +1,33 @@ +plugins { + id 'java' +} + +version '0.1.0' + +repositories { + mavenCentral() +} + +optimizedJar.enabled = false + +dependencies { + implementation "foundation.icon:icon-sdk:2.1.0" + implementation project(':score-lib') + annotationProcessor project(':score-client') + implementation project(':score-client') + implementation "org.junit.jupiter:junit-jupiter-api:5.8.2" + implementation "com.fasterxml.jackson.core:jackson-databind:2.13.3" + implementation "foundation.icon:javaee-unittest:0.9.4" + implementation "org.junit.jupiter:junit-jupiter:5.8.2" + runtimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.2" + implementation "com.github.sink772:minimal-json:0.9.7" + implementation "org.mockito:mockito-core:4.5.1" + implementation "org.json:json:20220320" + implementation "foundation.icon:javaee-scorex:0.5.2" + + implementation "com.github.javafaker:javafaker:1.0.2" +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/test-lib/conf/env.props b/test-lib/conf/env.props new file mode 100644 index 00000000..6d1b17d9 --- /dev/null +++ b/test-lib/conf/env.props @@ -0,0 +1,6 @@ +node.url=http://localhost:9082 +node.apiVersion=3 + +chain.nid=0x3 +chain.godWallet=godWallet.json +chain.godPassword=gochain diff --git a/test-lib/conf/godWallet.json b/test-lib/conf/godWallet.json new file mode 100644 index 00000000..2a611aa3 --- /dev/null +++ b/test-lib/conf/godWallet.json @@ -0,0 +1,22 @@ +{ + "address": "hxb6b5791be0b5ef67063b3c10b840fb81514db2fd", + "id": "87323a66-289a-4ce2-88e4-00278deb5b84", + "version": 3, + "coinType": "icx", + "crypto": { + "cipher": "aes-128-ctr", + "cipherparams": { + "iv": "069e46aaefae8f1c1f840d6b09144999" + }, + "ciphertext": "f35ff7cf4f5759cb0878088d0887574a896f7f0fc2a73898d88be1fe52977dbd", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 65536, + "r": 8, + "p": 1, + "salt": "0fc9c3b24cdb8175" + }, + "mac": "1ef4ff51fdee8d4de9cf59e160da049eb0099eb691510994f5eca492f56c817a" + } +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java new file mode 100644 index 00000000..8ac2e7db --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java @@ -0,0 +1,50 @@ +package community.icon.cps.score.test.integration; + +import foundation.icon.icx.KeyWallet; +import foundation.icon.jsonrpc.model.Hash; +import foundation.icon.jsonrpc.model.TransactionResult; +import foundation.icon.score.client.DefaultScoreClient; + +import community.icon.cps.score.lib.interfaces.CPSTreasuryInterfaceScoreClient; +import community.icon.cps.score.lib.interfaces.CPFTreasuryInterfaceScoreClient; + +import score.Address; + +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import static community.icon.cps.score.test.integration.ScoreIntegrationTest.*; +public class CPS { + public KeyWallet user; + public KeyWallet testUser; + + public KeyWallet owner; + + public CPSClient ownerClient; + public DefaultScoreClient cpsTreasury; + public DefaultScoreClient cpfTreasury; + + public CPSTreasuryInterfaceScoreClient cpsTreasuryScore; + public CPFTreasuryInterfaceScoreClient cpfTreasuryScore; + + Map cpsClients; + + public CPS() throws Exception{ + cpsClients = new HashMap<>(); + owner = createWalletWithBalance(BigInteger.TEN.pow(24)); + user = createWalletWithBalance(BigInteger.TEN.pow(24)); + testUser = createWalletWithBalance(BigInteger.TEN.pow(24)); + } + + public void setupCPS() throws Exception{ + registerPreps(); + deployContracts(); + } + + public void deployContracts(){ + cpsTreasury = deploy(owner, "CPSTreasury", null); + cpfTreasury = deploy(owner, "CPFTreasury", null); + } +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSClient.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSClient.java new file mode 100644 index 00000000..14a22959 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSClient.java @@ -0,0 +1,25 @@ +package community.icon.cps.score.test.integration; + +import foundation.icon.icx.KeyWallet; +import foundation.icon.score.client.DefaultScoreClient; + +import community.icon.cps.score.lib.interfaces.*; + +import static community.icon.cps.score.test.integration.ScoreIntegrationTest.chain; + +public class CPSClient { + private final KeyWallet wallet; + public CPSTreasuryInterfaceScoreClient cpsTreasury; + public CPFTreasuryInterfaceScoreClient cpfTreasury; + + public CPSClient(CPS cps, KeyWallet wallet){ + this.wallet = wallet; + cpsTreasury = new CPSTreasuryInterfaceScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + cps.cpsTreasury._address()); + cpfTreasury = new CPFTreasuryInterfaceScoreClient(chain.getEndpointURL(), chain.networkId, wallet, cps.cpfTreasury._address()); + } + + public score.Address getAddress() { + return score.Address.fromString(wallet.getAddress().toString()); + } +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSUtils.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSUtils.java new file mode 100644 index 00000000..e4a3ea2b --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSUtils.java @@ -0,0 +1,4 @@ +package community.icon.cps.score.test.integration; + +public class CPSUtils { +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/Env.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/Env.java new file mode 100644 index 00000000..d2fbadbf --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/Env.java @@ -0,0 +1,93 @@ +package community.icon.cps.score.test.integration; + +import foundation.icon.icx.KeyWallet; +import foundation.icon.icx.Wallet; +import foundation.icon.icx.crypto.KeystoreException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.Path; +import java.util.Properties; + +public class Env { + private static Chain chain; + + static { + String envFile = System.getProperty("env.props", "/Users/ibriz/icon-foundation-cps/cps_java_contracts/test-lib/conf/env.props"); + Properties props = new Properties(); + try { + FileInputStream fis = new FileInputStream(envFile); + props.load(fis); + fis.close(); + } catch (IOException e) { + System.err.printf("'%s' does not exist\n", envFile); + throw new IllegalArgumentException(e.getMessage()); + } + String confPath = Path.of(envFile).getParent().toString() + "/"; + readProperties(props, confPath); + } + + private static void readProperties(Properties props, String confPath) { + String chainName = "chain"; + String nid = props.getProperty(chainName + ".nid"); + if (nid == null) { + throw new IllegalArgumentException("nid not found"); + } + String godWalletPath = confPath + props.getProperty(chainName + ".godWallet"); + String godPassword = props.getProperty(chainName + ".godPassword"); + KeyWallet godWallet; + try { + godWallet = readWalletFromFile(godWalletPath, godPassword); + } catch (IOException e) { + throw new IllegalArgumentException(e.getMessage()); + } + String nodeName = "node"; + String url = props.getProperty(nodeName + ".url"); + if (url == null) { + throw new IllegalArgumentException("node url not found"); + } + + String apiVersion = props.getProperty(nodeName + ".apiVersion"); + if (apiVersion == null) { + throw new IllegalArgumentException("apiVersion not found"); + } + chain = new Chain(BigInteger.valueOf(Integer.parseInt(nid.substring(2), 16)), godWallet, url, apiVersion); + } + + private static KeyWallet readWalletFromFile(String path, String password) throws IOException { + try { + File file = new File(path); + return KeyWallet.load(password, file); + } catch (KeystoreException e) { + e.printStackTrace(); + throw new IOException("Key load failed!"); + } + } + + public static Chain getDefaultChain() { + if (chain == null) { + throw new AssertionError("Chain not found"); + } + return chain; + } + + public static class Chain { + public final BigInteger networkId; + public final Wallet godWallet; + private final String nodeUrl; + private final String apiVersion; + + public Chain(BigInteger networkId, Wallet godWallet, String url, String apiVersion) { + this.networkId = networkId; + this.godWallet = godWallet; + this.nodeUrl = url; + this.apiVersion = apiVersion; + } + + public String getEndpointURL() { + return this.nodeUrl + "/api/v" + apiVersion; + } + } +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java new file mode 100644 index 00000000..3034ede3 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java @@ -0,0 +1,224 @@ +package community.icon.cps.score.test.integration; + +import foundation.icon.icx.KeyWallet; +import foundation.icon.icx.Wallet; +import foundation.icon.jsonrpc.Address; +import foundation.icon.jsonrpc.model.Hash; +import foundation.icon.jsonrpc.model.TransactionResult; +import foundation.icon.score.client.DefaultScoreClient; +import foundation.icon.score.client.RevertedException; + +import community.icon.cps.score.lib.interfaces.SystemInterfaceScoreClient; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.function.Executable; +import score.UserRevertedException; + +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static community.icon.cps.score.test.integration.Env.Chain; +import static community.icon.cps.score.test.integration.Env.getDefaultChain; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Tag("integration") +@TestMethodOrder(value = MethodOrderer.OrderAnnotation.class) +public interface ScoreIntegrationTest { + Chain chain = getDefaultChain(); + DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, chain.godWallet, + DefaultScoreClient.ZERO_ADDRESS); + DefaultScoreClient client = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, null, null); + + SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); + + @SuppressWarnings("unchecked") + static void registerPreps() throws Exception { + + Map getPreps; + + try { + getPreps = systemScore.getPReps(BigInteger.ONE, BigInteger.valueOf(100)); + } catch (Exception e) { + registerPrep(); + getPreps = systemScore.getPReps(BigInteger.ONE, BigInteger.valueOf(100)); + } + + List> prepList = (List>) getPreps.get("preps"); + int prepCount = prepList.size(); + if (prepCount >= 100) { + return; + } + int remainingPrepsToRegister = 100 - prepCount; + for (int i = 0; i < remainingPrepsToRegister; i++) { + registerPrep(); + } + } + + private static void registerPrep() throws Exception { + KeyWallet owner = createWalletWithBalance(BigInteger.TEN.pow(24)); + DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner, + DefaultScoreClient.ZERO_ADDRESS); + SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); + systemScore.registerPRep(BigInteger.valueOf(2000).multiply(BigInteger.TEN.pow(18)), "test", + "kokoa@example.com", "USA", "New York", "https://icon.kokoa.com", + "https://icon.kokoa.com/json/details.json", "localhost:9082"); + } + + static KeyWallet createWalletWithBalance(BigInteger amount) throws Exception { + KeyWallet wallet = KeyWallet.create(); + Address address = DefaultScoreClient.address(wallet.getAddress().toString()); + transfer(address, amount); + return wallet; + } + + static void transfer(Address address, BigInteger amount) { + godClient._transfer(address, amount, null); + } + + static DefaultScoreClient deploy(Wallet wallet, String name, Map params) { + String path = getFilePath(name); + return DefaultScoreClient._deploy(chain.getEndpointURL(), chain.networkId, wallet, path, params); + } + + static Hash deployAsync(Wallet wallet, String name, Map params) { + String path = getFilePath(name); + return DefaultScoreClient._deployAsync(chain.getEndpointURL(), chain.networkId, wallet, path, params); + } + + static DefaultScoreClient getDeploymentResult(Wallet wallet, Hash hash) { + return DefaultScoreClient.getDeploymentResult(chain.getEndpointURL(), chain.networkId, wallet, hash); + } + + static String getFilePath(String key) { + String path = System.getProperty(key); + if (path == null) { + throw new IllegalArgumentException("No such property: " + key); + } + return path; + } + + static int indexOf(T[] array, T value) { + return indexOf(array, value::equals); + } + + static int indexOf(T[] array, Predicate predicate) { + for (int i = 0; i < array.length; i++) { + if (predicate.test(array[i])) { + return i; + } + } + return -1; + } + + static boolean contains(Map map, String key, Object value) { + return contains(map, key, value::equals); + } + + static boolean contains(Map map, String key, Predicate predicate) { + return map.containsKey(key) && predicate.test(map.get(key)); + } + + static List eventLogs(TransactionResult txr, String signature, Address scoreAddress, + Function mapperFunc, Predicate filter) { + Predicate predicate = (el) -> el.getIndexed().get(0).equals(signature); + if (scoreAddress != null) { + predicate = predicate.and((el) -> el.getScoreAddress().toString().equals(scoreAddress.toString())); + } + Stream stream = txr.getEventLogs().stream().filter(predicate).map(mapperFunc); + if (filter != null) { + stream = stream.filter(filter); + } + return stream.collect(Collectors.toList()); + } + + static void waitByNumOfBlock(long numOfBlock) { + waitByHeight(client._lastBlockHeight().add(BigInteger.valueOf(numOfBlock))); + } + + static void waitByHeight(long waitHeight) { + waitByHeight(BigInteger.valueOf(waitHeight)); + } + + static void waitByHeight(BigInteger waitHeight) { + BigInteger height = client._lastBlockHeight(); + while (height.compareTo(waitHeight) < 0) { + System.out.println("height: " + height + ", waitHeight: " + waitHeight); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + height = client._lastBlockHeight(); + } + } + + static void balanceCheck(Address address, BigInteger value, Executable executable) { + BigInteger balance = client._balance(address); + try { + executable.execute(); + } catch (UserRevertedException | RevertedException e) { + throw e; + } catch (Throwable e) { + throw new RuntimeException(e); + } + assertEquals(balance.add(value), client._balance(address)); + } + + @FunctionalInterface + interface EventLogsSupplier { + List apply(TransactionResult txr, Address address, Predicate filter); + } + + static Consumer eventLogChecker( + Address address, EventLogsSupplier supplier, Consumer consumer) { + return (txr) -> { + List eventLogs = supplier.apply(txr, address, null); + assertEquals(1, eventLogs.size()); + if (consumer != null) { + consumer.accept(eventLogs.get(0)); + } + }; + } + + static Consumer eventLogsChecker(Address address, EventLogsSupplier supplier, + Consumer> consumer) { + return (txr) -> { + List eventLogs = supplier.apply(txr, address, null); + if (consumer != null) { + consumer.accept(eventLogs); + } + }; + } + + static Consumer dummyConsumer() { + return (txr) -> { + + }; + } + + static Wallet getOrGenerateWallet(String prefix, Properties properties) { + Wallet wallet = DefaultScoreClient.wallet(prefix, properties); + return wallet == null ? generateWallet() : wallet; + } + + static KeyWallet generateWallet() { + try { + return KeyWallet.create(); + } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchProviderException e) { + throw new RuntimeException(e); + } + } +} + + From 43486009c92c1f178c4d9a83c915b2743ff5bd2b Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 2 Sep 2022 13:05:57 +0545 Subject: [PATCH 054/112] corrected the failing tests --- .../cps/score/cpstreasury/CPSTreasuryTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index a159db33..375b0981 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -140,37 +140,37 @@ void setBnUSDScoreExceptions(Boolean isAdmin, Address score_address) { @Test void setCpsScoreNotAdmin() { Executable setCpsScoreNotAdmin = () -> setCpsScoreExceptions(false, score_address); - expectErrorMessage(setCpsScoreNotAdmin, TAG + ": Only admins can call this method"); + expectErrorMessage(setCpsScoreNotAdmin, "Reverted(0): " + TAG + ": Only admins can call this method"); } @Test void setCpfTreasuryScoreNotAdmin() { Executable setCpfTreasuryScoreNotAdmin = () -> setCpfTreasuryScoreExceptions(false, score_address); - expectErrorMessage(setCpfTreasuryScoreNotAdmin, TAG + ": Only admins can call this method"); + expectErrorMessage(setCpfTreasuryScoreNotAdmin, "Reverted(0): " + TAG + ": Only admins can call this method"); } @Test void setBnUSDScoreNotAdmin() { Executable setBnUSDScoreNotAdmin = () -> setBnUSDScoreExceptions(false, score_address); - expectErrorMessage(setBnUSDScoreNotAdmin, TAG + ": Only admins can call this method"); + expectErrorMessage(setBnUSDScoreNotAdmin, "Reverted(0): " + TAG + ": Only admins can call this method"); } @Test void setCPSScoreNotContract() { Executable setCpsScoreNotAdmin = () -> setCpsScoreExceptions(true, testing_account.getAddress()); - expectErrorMessage(setCpsScoreNotAdmin, TAG + "Target " + testing_account.getAddress() + " is not a score."); + expectErrorMessage(setCpsScoreNotAdmin, "Reverted(0): " + TAG + "Target " + testing_account.getAddress() + " is not a score."); } @Test void setCPFTreasuryScoreNotContract() { Executable setCpfTreasuryScoreNotContract = () -> setCpfTreasuryScoreExceptions(true, testing_account.getAddress()); - expectErrorMessage(setCpfTreasuryScoreNotContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); + expectErrorMessage(setCpfTreasuryScoreNotContract, "Reverted(0): " + TAG + "Target " + testing_account.getAddress() + " is not a score."); } @Test void setBnUSDScoreNotContract() { Executable setBnUSDScoreContract = () -> setBnUSDScoreExceptions(true, testing_account.getAddress()); - expectErrorMessage(setBnUSDScoreContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); + expectErrorMessage(setBnUSDScoreContract, "Reverted(0): " + TAG + "Target " + testing_account.getAddress() + " is not a score."); } @Test @@ -219,7 +219,7 @@ void depositProposalFundExceptions(){ void depositProposalFundProposalAlreadyExists(){ depositProposalFundMethod(); Executable depositProposalFundProposalAlreadyExists = () -> depositProposalFundExceptions(); - expectErrorMessage(depositProposalFundProposalAlreadyExists, "CPS_TREASURY: Already have this project"); + expectErrorMessage(depositProposalFundProposalAlreadyExists, "Reverted(0): " + "CPS_TREASURY: Already have this project"); } @Test @@ -273,7 +273,7 @@ void updateProposalFundProposalException(){ @Test void updateProposalFundProposalDoesnotExist(){ Executable updateProposalFundProposalDoesnotExist = () -> updateProposalFundProposalException(); - expectErrorMessage(updateProposalFundProposalDoesnotExist, "CPS_TREASURY: Invalid IPFS hash."); + expectErrorMessage(updateProposalFundProposalDoesnotExist, "Reverted(0): " + "CPS_TREASURY: Invalid IPFS hash."); } @Test From 300570ec7456485a029ed57f181813470ff8b7f6 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 20:48:12 +0545 Subject: [PATCH 055/112] fix swapCount number by increasing the count prior to the swap --- .../java/community/icon/cps/score/cpftreasury/CPFTreasury.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java index 16966f43..b6d55b68 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java @@ -243,13 +243,13 @@ public void swap_tokens(int _count) { } else { BigInteger remainingICXToSwap = bnUSDRemainingToSwap.multiply(EXA).divide(icxbnUSDPrice.multiply(BigInteger.valueOf(count))); BigInteger icxBalance = Context.getBalance(Context.getAddress()); + swapCount.set(swapCountValue + 1); if (remainingICXToSwap.compareTo(icxBalance) > 0) { remainingICXToSwap = icxBalance; } if (remainingICXToSwap.compareTo(BigInteger.valueOf(5).multiply(EXA)) > 0) { swapIcxBnusd(remainingICXToSwap); - swapCount.set(swapCountValue + 1); } } } From 3ed7274a1938f58a086b34fc1185e02273983492 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 20:49:33 +0545 Subject: [PATCH 056/112] swapFlag implementation - setterGetter - implementing on ICXBnusd Swap --- .../cps/score/cpftreasury/CPFTreasury.java | 23 +++++++++++++++---- .../icon/cps/score/cpftreasury/Constants.java | 1 + 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java index b6d55b68..b24ffb31 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java @@ -33,8 +33,10 @@ public class CPFTreasury extends SetterGetter implements CPFTreasuryInterface { private final VarDB swapState = Context.newVarDB(SWAP_STATE, Integer.class); private final VarDB swapCount = Context.newVarDB(SWAP_COUNT, Integer.class); - public CPFTreasury() { + private final VarDB swapFlag = Context.newVarDB(SWAP_FLAG, Boolean.class); + public CPFTreasury() { + swapFlag.set(true); } private boolean proposalExists(String ipfsKey) { @@ -67,6 +69,17 @@ public void setMaximumTreasuryFundBnusd(BigInteger _value) { treasuryFundbnUSD.set(_value); } + @External + public void toggleSwapFlag() { + validateAdmins(); + swapFlag.set(!swapFlag.getOrDefault(false)); + } + + @External(readonly = true) + public boolean getSwapFlag() { + return swapFlag.getOrDefault(false); + } + private void burn(BigInteger amount) { Context.call(amount, SYSTEM_ADDRESS, "burn"); @@ -216,9 +229,11 @@ private void swapTokens(Address _from, Address _to, BigInteger _amount) { @Override @External public void swapIcxBnusd(BigInteger amount) { - Address[] path = new Address[]{sICXScore.get(), balancedDollar.get()}; - Object[] params = new Object[]{path}; - Context.call(amount, routerScore.get(), "route", params); + if (getSwapFlag()) { + Address[] path = new Address[]{sICXScore.get(), balancedDollar.get()}; + Object[] params = new Object[]{path}; + Context.call(amount, routerScore.get(), "route", params); + } } @Override diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java index 7c92451a..a603c678 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java @@ -26,6 +26,7 @@ public class Constants { public static final String SWAP_STATE = "swap_state"; public static final String SWAP_COUNT = "swap_count"; + public static final String SWAP_FLAG = "swap_flag"; public static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000"); public static final int sICXICXPoolID = 1; From 24b4da5466b1a3ff6a87f2dd8b713cf400c955d6 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 21:28:22 +0545 Subject: [PATCH 057/112] update gitIgnore --- .gitignore | 52 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index a2c5c73d..6151cd4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,38 @@ -keystore.json -keystore -gradle.properties -.gradle +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* .idea -keystore.zip -lib -CPSTreasury.iml -CPFTreasury/build -CPSTreasury/build -gochain-local/ -goloop/ -CPSTreasury/.DS_Store -CPSTreasury/src/.DS_Store -.DS_Store -score-client/build -score-lib/build -test-lib/build -testinteg/build +.gradle +**/build/ +!gradle-wrapper.jar + +gradle.properties +*.json +.deployment +.project +.classpath +.settings +**/bin/ From c2311d8ac84d4a09ecbbd125c5425fa474691a34 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 21:28:41 +0545 Subject: [PATCH 058/112] update project build.gradle --- build.gradle | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/build.gradle b/build.gradle index 2fd7aebe..1e59de7f 100644 --- a/build.gradle +++ b/build.gradle @@ -14,37 +14,6 @@ task buildContracts(type: Exec) { commandLine './gradlew', 'optimizedJar' } -//apply plugin: 'deploy-contracts' -//deployCPSContracts { -// envs { -// local { -// env = "local" -// } -// berlin { -// env = "berlin" -// configFile = "contracts-sample.json" -// keystore = rootProject.findProperty('keystoreName') ?: '' -// password = rootProject.findProperty('keystorePass') ?: '' -// } -// sejong { -// env = "sejong" -// configFile = "contracts-sample.json" -// keystore = rootProject.findProperty('keystoreName') ?: '' -// password = rootProject.findProperty('keystorePass') ?: '' -// } -// } -//} - - -//executeBalancedActions { -// contractAddressFile = "sample.json" -// propertiesFile = "sample.properties" -// actionsFile = "actions-sample.json" -// keystore = rootProject.findProperty('keystoreName') ?: '' -// password = rootProject.findProperty('keystorePass') ?: '' -//} - - subprojects { repositories { mavenCentral() From 46151a86e1d19aa7c35831f105e2e79bc8058976 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 21:29:09 +0545 Subject: [PATCH 059/112] update project settings.gradle --- settings.gradle | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/settings.gradle b/settings.gradle index 1e359454..6a1b5a45 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,12 +1,32 @@ rootProject.name = 'cps_java_contracts' include (':CPFTreasury') +project(':CPFTreasury').projectDir = file("CPFTreasury") include (':CPSTreasury') project(':CPSTreasury').projectDir = file("CPSTreasury") +include (':CPSMain') +project(':CPSMain').projectDir = file("CPSMain") + include ('score-client') include ('test-lib') include ('score-lib') + +include (':Router') +project(':Router').projectDir = file("dummy/Router") + +include (':Dex') +project(':Dex').projectDir = file("dummy/Dex") + +include (':sICX') +project(':sICX').projectDir = file("dummy/sICX") + +include (':bnUSD') +project(':bnUSD').projectDir = file("dummy/bnUSD") + + + + From c218c2611b8d349648c4a8c66684538dac40f528 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 22:02:16 +0545 Subject: [PATCH 060/112] update project `settings.gradle` --- settings.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings.gradle b/settings.gradle index 6a1b5a45..1c83786f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,8 +6,8 @@ project(':CPFTreasury').projectDir = file("CPFTreasury") include (':CPSTreasury') project(':CPSTreasury').projectDir = file("CPSTreasury") -include (':CPSMain') -project(':CPSMain').projectDir = file("CPSMain") +include (':CPSCore') +project(':CPSCore').projectDir = file("CPSCore") include ('score-client') From 035cf9ed10c4969b8b52c0049261e39a86a062fe Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 22:04:31 +0545 Subject: [PATCH 061/112] update CPSCore build.gradle --- CPSCore/build.gradle | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 CPSCore/build.gradle diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle new file mode 100644 index 00000000..e4579daf --- /dev/null +++ b/CPSCore/build.gradle @@ -0,0 +1,61 @@ +version = '0.9.1' + +dependencies { + compileOnly 'foundation.icon:javaee-api:0.9.1' + implementation 'com.github.sink772:minimal-json:0.9.7' + implementation 'foundation.icon:javaee-scorex:0.5.2' + + implementation project(':score-lib') + testImplementation project(':test-lib') + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation('org.mockito:mockito-inline:4.5.1') + testImplementation 'foundation.icon:javaee-unittest:0.9.4' + intTestImplementation "foundation.icon:icon-sdk:2.1.0" + intTestImplementation project(":score-client") + intTestAnnotationProcessor project(":score-client") + + + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + + +} + +optimizedJar { + mainClassName = 'community.icon.cps.score.cpscore.CPSCore' + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +deployJar { + endpoints { + lisbon { + uri = 'https://lisbon.net.solidwallet.io/api/v3' + nid = 0x2 + } + local { + uri = 'http://localhost:9082/api/v3' + nid = 0x3 + } + sejong { + uri = 'https://sejong.net.solidwallet.io/api/v3' + nid = 0x53 + + } + berlin { + uri = 'https://berlin.net.solidwallet.io/api/v3' + nid = 0x7 + to = 'cx9c7017aca210ed21c5d043641ab3e30d1336a19e' + } + } + keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' + password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' + parameters { + } +} + +test { + useJUnitPlatform() +} From 4e6d3e695960aa97678b93d376460df0d0213fbf Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 22:09:46 +0545 Subject: [PATCH 062/112] Translate CPS Main Score to Java - Include subsidiary files ArrayDBUtils, Constants, PReps, PeriodController, Checkers, SetterGetter - Update ProposalDb and ProgressReportDataDb --- .../icon/cps/score/cpscore/CPSCore.java | 2541 +++++++++++++++++ .../icon/cps/score/cpscore/PReps.java | 28 + .../cps/score/cpscore/PeriodController.java | 17 + .../icon/cps/score/cpscore/SetterGetter.java | 22 + .../cpscore/db/ProgressReportDataDb.java | 91 + .../cps/score/cpscore/db/ProposalDataDb.java | 107 + .../cps/score/cpscore/utils/ArrayDBUtils.java | 156 + .../cps/score/cpscore/utils/Checkers.java | 34 + .../cps/score/cpscore/utils/Constants.java | 189 ++ 9 files changed, 3185 insertions(+) create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/PReps.java create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/PeriodController.java create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/SetterGetter.java create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/ArrayDBUtils.java create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Checkers.java create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java new file mode 100644 index 00000000..1e093254 --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -0,0 +1,2541 @@ +package community.icon.cps.score.cpscore; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonObject; +import community.icon.cps.score.cpscore.db.ProgressReportDataDb; +import community.icon.cps.score.cpscore.db.ProposalDataDb; +import community.icon.cps.score.cpscore.utils.ArrayDBUtils; +import score.*; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Optional; +import score.annotation.Payable; +import scorex.util.HashMap; + +import java.math.BigInteger; +import scorex.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static community.icon.cps.score.cpscore.db.ProgressReportDataDb.*; +import static community.icon.cps.score.cpscore.db.ProposalDataDb.*; +import static community.icon.cps.score.cpscore.utils.Constants.*; +import static community.icon.cps.score.cpscore.utils.Checkers.*; +import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface; + +public class CPSCore implements CPSCoreInterface { + + private final ArrayDB proposalsKeyList = Context.newArrayDB(PROPOSALS_KEY_LIST, String.class); + private final DictDB proposalsKeyListIndex = Context.newDictDB(PROPOSALS_KEY_LIST_INDEX, Integer.class); + private final ArrayDB progressKeyList = Context.newArrayDB(PROGRESS_KEY_LIST, String.class); + private final DictDB progressKeyListIndex = Context.newDictDB(PROGRESS_KEY_LIST_INDEX, Integer.class); + private final ArrayDB budgetApprovalsList = Context.newArrayDB(BUDGET_APPROVALS_LIST, String.class); + + private final ArrayDB activeProposals = Context.newArrayDB(ACTIVE_PROPOSALS, String.class); + private final ArrayDB votingProposals = Context.newArrayDB(VOTING_PROPOSALS, String.class); + private final ArrayDB votingProgressReports = Context.newArrayDB(VOTING_PROGRESS_REPORTS, String.class); + + private final ArrayDB
contributors = Context.newArrayDB(CONTRIBUTORS, Address.class); + private final ArrayDB
sponsors = Context.newArrayDB(SPONSORS, Address.class); + private static final ArrayDB
admins = Context.newArrayDB(ADMINS, Address.class); + private final ArrayDB sponsorPending = Context.newArrayDB(SPONSOR_PENDING, String.class); + private final ArrayDB pending = Context.newArrayDB(PENDING, String.class); + private final ArrayDB active = Context.newArrayDB(ACTIVE, String.class); + private final ArrayDB paused = Context.newArrayDB(PAUSED, String.class); + private final ArrayDB completed = Context.newArrayDB(COMPLETED, String.class); + private final ArrayDB rejected = Context.newArrayDB(REJECTED, String.class); + private final ArrayDB disqualified = Context.newArrayDB(DISQUALIFIED, String.class); + public final Map> proposalStatus = Map.of(SPONSOR_PENDING, sponsorPending, + PENDING, pending, + ACTIVE, active, + PAUSED, paused, + COMPLETED, completed, + REJECTED, rejected, + DISQUALIFIED, disqualified); + + + private final ArrayDB waitingProgressReports = Context.newArrayDB(WAITING, String.class); + private final ArrayDB approvedProgressReports = Context.newArrayDB(APPROVED, String.class); + private final ArrayDB progressRejected = Context.newArrayDB(PROGRESS_REPORT_REJECTED, String.class); + public final Map> progressReportStatus = Map.of(WAITING, waitingProgressReports, + APPROVED, approvedProgressReports, + PROGRESS_REPORT_REJECTED, progressRejected + ); + + private final BranchDB> sponsorBondReturn = Context.newBranchDB(SPONSOR_BOND_RETURN, BigInteger.class); + private final DictDB delegationSnapshot = Context.newDictDB(DELEGATION_SNAPSHOT, BigInteger.class); + private final VarDB maxDelegation = Context.newVarDB(MAX_DELEGATION, BigInteger.class); + private final VarDB proposalFees = Context.newVarDB(PROPOSAL_FEES, BigInteger.class); + private final VarDB swapBlockHeight = Context.newVarDB(SWAP_BLOCK_HEIGHT, BigInteger.class); + private final VarDB swapCount = Context.newVarDB(SWAP_COUNT, Integer.class); + private final DictDB proposalRank = Context.newDictDB(PROPOSAL_RANK, Integer.class); + private final ArrayDB
priorityVotedPreps = Context.newArrayDB(PRIORITY_VOTED_PREPS, Address.class); + + public CPSCore() { + PeriodController periodController = new PeriodController(); + periodController.periodCount.set(19); + } + + @Override + @External(readonly = true) + public String name() { + return TAG; + } + + @Override + public String proposalPrefix(String proposalKey) { + return PROPOSAL_DB_PREFIX + "|" + "|" + proposalKey; + } + + @Override + public String progressReportPrefix(String progressKey) { + return PROGRESS_REPORT_DB_PREFIX + "|" + "|" + progressKey; + } + + /*** + * Deprecated because JAVA convention will be used in the future versions for method name and parameter name + * i.e. set_cps_treasury_score -> setCpsTreasuryScore and _score -> score + * @param _score: Address of CPS Treasury Score + */ + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void set_cps_treasury_score(Address _score) { + setCpsTreasuryScore(_score); + } + + @Override + @External + public void setCpsTreasuryScore(Address score){ + validateAdminScore(score); + SetterGetter setterGetter = new SetterGetter(); + setterGetter.cpsTreasuryScore.set(score); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Address get_cps_treasury_score() { + return getCpsTreasuryScore(); + } + + @Override + @External(readonly = true) + public Address getCpsTreasuryScore(){ + SetterGetter setterGetter = new SetterGetter(); + return setterGetter.cpsTreasuryScore.get(); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void set_cpf_treasury_score(Address _score) { + setCpfTreasuryScore(_score); + } + + @Override + @External + public void setCpfTreasuryScore(Address score) { + validateAdminScore(score); + SetterGetter setterGetter = new SetterGetter(); + setterGetter.cpfScore.set(score); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Address get_cpf_treasury_score() { + return getCpfTreasuryScore(); + } + + @Override + @External(readonly = true) + public Address getCpfTreasuryScore(){ + SetterGetter setterGetter = new SetterGetter(); + return setterGetter.cpfScore.get(); + } + + + + @External + public void setBnusdScore(Address score) { + validateAdminScore(score); + SetterGetter setterGetter = new SetterGetter(); + setterGetter.balancedDollar.set(score); + } + + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void set_bnUSD_score(Address _score) { + setBnusdScore(_score); + } + + @External(readonly = true) + public Address getBnusdScore() { + SetterGetter setterGetter = new SetterGetter(); + return setterGetter.balancedDollar.get(); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Address get_bnUSD_score() { + return getBnusdScore(); + } + + private boolean proposalKeyExists(String key) { + return proposalsKeyListIndex.get(key) != null; + } + + private boolean _progress_key_exists(String key) { + return progressKeyListIndex.get(key) != null; + } + + @External(readonly = true) + public boolean isAdmin(Address address) { + return ArrayDBUtils.containsInArrayDb(address, admins); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public boolean is_admin(Address _address) { + return isAdmin(_address); + } + + @Override + @External + public void toggleBudgetAdjustmentFeature() { + SetterGetter setterGetter = new SetterGetter(); + setterGetter.budgetAdjustment.set(!setterGetter.budgetAdjustment.getOrDefault(false)); + } + + @Override + @External(readonly = true) + public boolean getBudgetAdjustmentFeature() { + SetterGetter setterGetter = new SetterGetter(); + return setterGetter.budgetAdjustment.get(); + } + + @External + public void toggleMaintenance() { + validateAdmins(); + SetterGetter setterGetter = new SetterGetter(); + setterGetter.maintenance.set(!setterGetter.maintenance.getOrDefault(Boolean.TRUE)); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void toggle_maintenance() { + toggleMaintenance(); + } + + @Override + @External(readonly = true) + public boolean getMaintenanceMode() { + SetterGetter setterGetter = new SetterGetter(); + return setterGetter.maintenance.getOrDefault(false); + } + + @Override + @Payable + public void fallback() { + Context.revert("ICX can only be sent while submitting a proposal or paying the penalty."); + } + + private void burn(BigInteger amount, @Optional Address token) { + SetterGetter setterGetter = new SetterGetter(); + if (token == null) { + token = SYSTEM_ADDRESS; + } + if (token.equals(SYSTEM_ADDRESS)) { + callScore(amount, SYSTEM_ADDRESS, "burn"); + } else { + Address bnUSDScore = setterGetter.balancedDollar.get(); + if (token.equals(bnUSDScore)) { + JsonObject burnTokens = new JsonObject(); + burnTokens.add("method", "burn_amount"); + callScore(bnUSDScore, "transfer", setterGetter.cpfScore.get(), amount, burnTokens.toString().getBytes()); + } else { + Context.revert(TAG + ": Not a supported token."); + } + } + } + + @Override + @External(readonly = true) + public int getPeriodCount(){ + PeriodController periodController = new PeriodController(); + return periodController.periodCount.get(); + } + + @External + public void addAdmin(Address address) { +// TODO check governance contract + onlyOwner(); + boolean check = ArrayDBUtils.containsInArrayDb(address, admins); + if (!check) { + admins.add(address); + } + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void add_admin(Address _address) { + addAdmin(_address); + } + + @External + public void removeAdmin(Address address) { // change made + onlyOwner(); + Context.require(address != Context.getOwner(), "Owner cannot be removed from admin list."); + boolean check = ArrayDBUtils.containsInArrayDb(address, admins); + Context.require(check, TAG + ": Address not registered as admin."); + ArrayDBUtils.removeArrayItem(admins, address); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void remove_admin(Address _address) { // change made + removeAdmin(_address); + } + + @External + public void unregisterPrep() { + checkMaintenance(); + update_period(); + Address caller = Context.getCaller(); + PReps pReps = new PReps(); + PeriodController period = new PeriodController(); + Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps) && + ArrayDBUtils.containsInArrayDb(caller, pReps.registeredPreps), "P-Rep is not registered yet."); + Context.require(period.periodName.get().equals(APPLICATION_PERIOD), + "P-Reps can only be unregister on Application Period"); + ArrayDBUtils.removeArrayItem(pReps.validPreps, caller); + ArrayDBUtils.removeArrayItem(pReps.registeredPreps, caller); + pReps.unregisteredPreps.add(caller); + UnRegisterPRep(caller, "P-Rep has ben unregistered successfully."); + + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void unregister_prep() { + unregisterPrep(); + } + + @External + public void registerPrep() { + checkMaintenance(); + update_period(); + Address caller = Context.getCaller(); + List
prepList = getPrepsAddress(); + PReps pReps = new PReps(); + + Context.require(prepList.contains(caller), + TAG + ": Not a P-Rep."); + Context.require(!ArrayDBUtils.containsInArrayDb(caller, pReps.registeredPreps), + TAG + ": P-Rep is already registered."); + Context.require(!ArrayDBUtils.containsInArrayDb(caller, pReps.denylist), + TAG + ": You are in denylist. To register, You've to pay Penalty."); + + if (ArrayDBUtils.containsInArrayDb(caller, pReps.unregisteredPreps)) { + ArrayDBUtils.removeArrayItem(pReps.unregisteredPreps, caller); + } + pReps.registeredPreps.add(caller); + RegisterPRep(caller, "P-Rep Registered."); + PeriodController period = new PeriodController(); + if (period.periodName.get().equals(APPLICATION_PERIOD)) { + pReps.validPreps.add(caller); + } + + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void register_prep() { + registerPrep(); + } + + @SuppressWarnings("unchecked") + private List> getPrepTerm() { + Map prepDict = callScore(Map.class, SYSTEM_ADDRESS, "getPRepTerm"); + return (List>) prepDict.get("preps"); + } + + + private List
getPrepsAddress() { + List
prepsList = new ArrayList<>(); + for (Map preps : getPrepTerm()) { + Address prepAddress = (Address) preps.get("address"); + prepsList.add(prepAddress); + } + return prepsList; + } + + private String getPrepName(Address address) { + for (Map preps : getPrepTerm()) { + Address prepAddress = (Address) preps.get("address"); + if (prepAddress.equals(address)) { + return (String) preps.get("name"); + } + } + return ""; + } + + private BigInteger getStake(Address address) { + for (Map preps : getPrepTerm()) { + Address prepAddress = (Address) preps.get("address"); + if (prepAddress.equals(address)) { + return (BigInteger) preps.get("power"); + } + } + return BigInteger.ZERO; + } + + private void setPreps() { + PReps pReps = new PReps(); + ArrayDBUtils.clearArrayDb(pReps.validPreps); + List
prepsList = getPrepsAddress(); + + for (Address prep : prepsList) { + if (!ArrayDBUtils.containsInArrayDb(prep, pReps.denylist) && + !ArrayDBUtils.containsInArrayDb(prep, pReps.unregisteredPreps)) { + if (ArrayDBUtils.containsInArrayDb(prep, pReps.registeredPreps)) { + pReps.validPreps.add(prep); + } + } + } + + } + + private void removeSponsor(Address address) { + Context.require(ArrayDBUtils.containsInArrayDb(address, sponsors), + address + " not on sponsor list."); + ArrayDBUtils.removeArrayItem(sponsors, address); + } + + private void removeContributor(Address address) { + Context.require(ArrayDBUtils.containsInArrayDb(address, contributors), + address + " not on contributor list."); + ArrayDBUtils.removeArrayItem(contributors, address); + } + + @External(readonly = true) + public List getProposalKeys() { + List proposalKeys = new ArrayList<>(); + for (int i = 0; i < proposalsKeyList.size(); i++) { + proposalKeys.add(proposalsKeyList.get(i)); + + } + return proposalKeys; + + } + + @External(readonly = true) + public List getProgressKeys() { + List progressKeys = new ArrayList<>(); + for (int i = 0; i < progressKeyList.size(); i++) { + progressKeys.add(progressKeyList.get(i)); + + } + return progressKeys; + + } + + private BigInteger getPenaltyAmount(Address address) { + PReps pReps = new PReps(); + Integer count = pReps.prepsDenylistStatus.getOrDefault(address.toString(), 0); + Context.require(count != 0, address + " doesn't need to pay any penalty."); + + int idx = count < 3 ? count - 1 : 2; + BigInteger amount = pReps.penaltyAmount.get(idx); + BigInteger delegationAmount = getStake(address); + return delegationAmount.multiply(amount).divide(maxDelegation.get()); + } + + @Override + @External(readonly = true) + public boolean checkPriorityVoting(Address prep) { + return ArrayDBUtils.containsInArrayDb(prep, priorityVotedPreps); + } + + @Override + @External(readonly = true) + public List sortPriorityProposals() { + String[] pendingProposals = new String[pending.size()]; + for (int i = 0; i < pending.size(); i++){ + pendingProposals[i] = pending.get(i); + } + mergeSort(pendingProposals, 0, pending.size() - 1, getPriorityVoteResult()); + return arrayToList(pendingProposals); + } + + @Override + @External(readonly = true) + public Map getPriorityVoteResult() { + Map priorityVoteResult = new HashMap<>(); + + for (int i = 0; i < pending.size(); i++) { + String prop = pending.get(i); + priorityVoteResult.put(prop, proposalRank.get(prop)); + + } + return priorityVoteResult; + } + + + @Override + @External + public void votePriority(String[] _proposals) { + PeriodController period = new PeriodController(); + Context.require(period.periodName.get().equals(VOTING_PERIOD), TAG + ": Voting can only be done in Voting Period."); + Address caller = Context.getCaller(); + PReps pReps = new PReps(); + Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps), "Voting can only be done by registered P-Reps"); + Context.require(!checkPriorityVoting(caller), "Already voted for Priority Ranking."); + + priorityVotedPreps.add(caller); + int size = _proposals.length; + for (int i = 0; i < size; i++) { + String proposal = _proposals[i]; + Context.require(ArrayDBUtils.containsInArrayDb(proposal, pending), + proposal + " not in pending state."); + proposalRank.set(proposal, proposalRank.getOrDefault(proposal, 0) + size - i); + } + PriorityVote(caller, "Priority voting done successfully."); + } + + @External + public void setPrepPenaltyAmount(BigInteger[] penalty) { + checkMaintenance(); + validateAdmins(); + Context.require(penalty.length == PENALTY_LEVELS, TAG + ": Exactly 3 Penalty amount Required."); + PReps pReps = new PReps(); + for (int i = 0; i < PENALTY_LEVELS; i++) { + BigInteger amount = penalty[i]; + Context.require(amount.compareTo(BigInteger.ZERO) >= 0, "Invalid amount" + amount); + pReps.penaltyAmount.add(amount.multiply(EXA)); + } + + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void set_prep_penalty_amount(BigInteger[] _penalty){ + setPrepPenaltyAmount(_penalty); + } + + + @External + public void setInitialBlock() { + validateAdmins(); + setPreps(); + PeriodController period = new PeriodController(); + period.initialBlock.set(BigInteger.valueOf(Context.getBlockHeight())); + period.nextBlock.set(BigInteger.valueOf(Context.getBlockHeight()).add(BLOCKS_DAY_COUNT.multiply(DAY_COUNT))); + period.periodName.set(APPLICATION_PERIOD); + period.previousPeriodName.set("None"); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void set_initialBlock() { + setInitialBlock(); + } + + @External(readonly = true) + public Map loginPrep(Address address) { // added for is prep but not registered + Map loginData = new HashMap<>(); + List
allPreps = getPrepsAddress(); + PReps pReps = new PReps(); + if (allPreps.contains(address)) { + loginData.put("isPRep", BigInteger.ONE); + if (ArrayDBUtils.containsInArrayDb(address, pReps.unregisteredPreps)) { + loginData.put("isRegistered", BigInteger.ZERO); + loginData.put("payPenalty", BigInteger.ZERO); + loginData.put("votingPRep", BigInteger.ZERO); + + } + else if (ArrayDBUtils.containsInArrayDb(address, pReps.denylist)) { + loginData.put("isRegistered", BigInteger.ZERO); + loginData.put("payPenalty", BigInteger.ONE); + loginData.put("votingPRep", BigInteger.ZERO); + loginData.put("penaltyAmount", getPenaltyAmount(address)); + } +// If a P-Rep registers on Voting period, P-Rep status will be registered. + else if (ArrayDBUtils.containsInArrayDb(address, pReps.registeredPreps)) { + loginData.put("isRegistered", BigInteger.ONE); + loginData.put("payPenalty", BigInteger.ZERO); + loginData.put("votingPRep", BigInteger.ZERO); + + if (ArrayDBUtils.containsInArrayDb(address, pReps.validPreps)) { + loginData.put("votingPRep", BigInteger.ONE); + } + } else { + loginData.put("isRegistered", BigInteger.ZERO); + loginData.put("payPenalty", BigInteger.ZERO); + loginData.put("votingPRep", BigInteger.ZERO); + } + + } else { + loginData.put("isPRep", BigInteger.ZERO); + loginData.put("isRegistered", BigInteger.ZERO); + loginData.put("payPenalty", BigInteger.ZERO); + loginData.put("votingPRep", BigInteger.ZERO); + + } + return loginData; + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map login_prep(Address _address) { + return loginPrep(_address); + } + + @External(readonly = true) + public List
getAdmins() { + List
adminList = new ArrayList<>(); + for (int i = 0; i < admins.size(); i++) { + adminList.add(admins.get(i)); + + } + return adminList; + + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public List
get_admins() { + return getAdmins(); + } + + @External(readonly = true) + public Map getRemainingFund() { + SetterGetter setterGetter = new SetterGetter(); + //noinspection unchecked + return callScore(Map.class, setterGetter.cpfScore.get(), "get_total_funds"); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_remaining_fund() { + return getRemainingFund(); + } + + @External(readonly = true) + public List> getPReps() { + List> prepsList = new ArrayList<>(); + PReps pReps = new PReps(); + for (int i = 0; i < pReps.validPreps.size(); i++) { + Address prep = pReps.validPreps.get(i); + Map prepData = new HashMap<>(); + prepData.put("name", getPrepName(prep)); + prepData.put("address", prep.toString()); + prepData.put("delegated", getStake(prep).toString()); + prepsList.add(prepData); + } + return prepsList; + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public List> get_PReps() { + return getPReps(); + } + + @External(readonly = true) + public List
getDenylist() { + List
denyList = new ArrayList<>(); + PReps pReps = new PReps(); + for (int i = 0; i < pReps.denylist.size(); i++) { + denyList.add(pReps.denylist.get(i)); + } + return denyList; + + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public List
get_denylist() { + return getDenylist(); + } + + @External(readonly = true) + public Map getPeriodStatus() { // added getOrDefault in next block + PeriodController period = new PeriodController(); + BigInteger remainingTime = period.nextBlock.getOrDefault(BigInteger.ZERO).subtract(BigInteger.valueOf(Context.getBlockHeight())).multiply(BigInteger.valueOf(2)); + if (remainingTime.compareTo(BigInteger.ZERO) < 0) { + remainingTime = BigInteger.ZERO; + } + return Map.of(CURRENTBLOCK, Context.getBlockHeight(), + NEXTBLOCK, period.nextBlock.getOrDefault(BigInteger.valueOf(0)), + REMAINING_TIME, remainingTime, + PERIOD_NAME, period.periodName.getOrDefault("None"), + PREVIOUS_PERIOD_NAME, period.previousPeriodName.getOrDefault("None"), + PERIOD_SPAN, BLOCKS_DAY_COUNT.multiply(DAY_COUNT).multiply(BigInteger.valueOf(2))); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_period_status() { + return getPeriodStatus(); + } + + @External(readonly = true) + public List
getContributors() { + List
contributors = new ArrayList<>(); + PReps pReps = new PReps(); + for (int i = 0; i < this.contributors.size(); i++) { + contributors.add(this.contributors.get(i)); + + } + return contributors; + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public List
get_contributors() { + return getContributors(); + } + + + @External(readonly = true) + public Map checkClaimableSponsorBond(Address address) { + DictDB userAmounts = sponsorBondReturn.at(address.toString()); + return Map.of(ICX, userAmounts.getOrDefault(ICX, BigInteger.ZERO), + bnUSD, userAmounts.getOrDefault(bnUSD, BigInteger.ZERO)); + + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map check_claimable_sponsor_bond(Address _address) { + return checkClaimableSponsorBond(_address); + } + + @SuppressWarnings("unchecked") + private BigInteger getMaxCapBNUsd() { + SetterGetter setterGetter = new SetterGetter(); + Map cpfAmount = callScore(Map.class, setterGetter.cpfScore.get(), "get_remaining_swap_amount"); + return cpfAmount.get("maxCap"); + } + + @Payable + @External + public void submitProposal(ProposalAttributes proposals) { + checkMaintenance(); + update_period(); + PeriodController period = new PeriodController(); + Context.require(period.periodName.get().equals(APPLICATION_PERIOD), + TAG + ": Proposals can only be submitted on Application Period "); + Context.require(!Context.getCaller().isContract(), TAG + ": Contract Address not supported."); + Context.require(proposals.project_duration <= MAX_PROJECT_PERIOD, + TAG + ": Maximum Project Duration exceeds " + MAX_PROJECT_PERIOD + " months."); + BigInteger projectBudget = proposals.total_budget.multiply(EXA); + BigInteger maxCapBNUsd = getMaxCapBNUsd(); + Context.require(projectBudget.compareTo(maxCapBNUsd) < 0, + TAG + ": " + projectBudget + "is greater than MAX CAP " + maxCapBNUsd); + PReps pReps = new PReps(); + Context.require(ArrayDBUtils.containsInArrayDb(proposals.sponsor_address, pReps.validPreps), + TAG + ": Sponsor P-Rep not a Top 100 P-Rep."); + Context.require(Context.getValue().equals(BigInteger.valueOf(APPLICATION_FEE).multiply(EXA)), + TAG + ": Deposit " + APPLICATION_FEE + " ICX to submit a proposal."); + String tokenFlag = proposals.token; + Context.require(tokenFlag.equals(bnUSD), TAG + ": " + tokenFlag + " Not a supported token."); + + ProposalAttributes proposalAttributes = new ProposalAttributes(); + String ipfsHash = proposals.ipfs_hash; + String ipfsHashPrefix = proposalPrefix(ipfsHash); + +// TODO Check if prefix is already added or not + addDataToProposalDB(proposals, ipfsHashPrefix); + proposalsKeyList.add(proposals.ipfs_hash); + proposalsKeyListIndex.set(ipfsHash, proposalsKeyList.size() - 1); + sponsorPending.add(ipfsHash); + contributors.add(Context.getCaller()); + ProposalSubmitted(Context.getCaller(), "Successfully submitted a Proposal."); + + BigInteger totalFund = proposalFees.getOrDefault(BigInteger.ZERO); + BigInteger halfProposalFee = Context.getValue().divide(BigInteger.TWO); + proposalFees.set(totalFund.add(halfProposalFee)); + burn(halfProposalFee, null); + swapBNUsdToken(); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @Payable + @External + public void submit_proposal(ProposalAttributes _proposals) { + submitProposal(_proposals); + } + + @External + public void voteProposal(String ipfsKey, String vote, String voteReason, @Optional boolean voteChange) { + checkMaintenance(); + update_period(); + PeriodController period = new PeriodController(); + Context.require(period.periodName.get().equals(VOTING_PERIOD), + TAG + ": Proposals can be voted only on Voting Period."); + Address caller = Context.getCaller(); + PReps pReps = new PReps(); + Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps), + TAG + ": Voting can only be done by registered P-Reps."); + Context.require(List.of(APPROVE, REJECT, ABSTAIN).contains(vote), + TAG + ": Vote should be either _approve, _reject or _abstain"); + + Map proposalDetails = getProposalDetails(ipfsKey); + String proposalPrefix = proposalPrefix(ipfsKey); + String status = (String) proposalDetails.get(STATUS); + + ArrayDB
voterList = ProposalDataDb.votersList.at(proposalPrefix); + + if (!voteChange) { + if (ArrayDBUtils.containsInArrayDb(caller, voterList)) { + Context.revert(TAG + ": Already Voted"); + } + } + Context.require(status.equals(PENDING), TAG + ": Proposal must be done in Voting state."); + + BigInteger voterStake = delegationSnapshot.get(String.valueOf(caller)); + BigInteger totalVotes = (BigInteger) proposalDetails.get(TOTAL_VOTES); + BigInteger approvedVotes = (BigInteger) proposalDetails.get(APPROVED_VOTES); + BigInteger rejectedVotes = (BigInteger) proposalDetails.get(REJECTED_VOTES); + BigInteger abstainedVotes = (BigInteger) proposalDetails.get(ABSTAINED_VOTES); + Integer totalVoter = (Integer) proposalDetails.get(TOTAL_VOTERS); + if (totalVoter == 0) { + ProposalDataDb.totalVoters.at(proposalPrefix).set(pReps.validPreps.size()); + } + + DictDB votersIndexDb = votersListIndex.at(proposalPrefix).at(caller); + + if (!voteChange) { + ProposalDataDb.totalVotes.at(proposalPrefix).set(totalVotes.add(voterStake)); + ProposalDataDb.votersList.at(proposalPrefix).add(caller); + votersIndexDb.set(INDEX, ProposalDataDb.votersList.at(proposalPrefix).size()); + ProposalDataDb.votersReasons.at(proposalPrefix).add(voteReason); + } else { + Context.require(votersIndexDb.getOrDefault(CHANGE_VOTE, 0) == 0, + TAG + ": Vote change can be done only once."); + votersIndexDb.set(CHANGE_VOTE, 1); + int index = votersIndexDb.getOrDefault(INDEX, 0); + int voteIndex = votersIndexDb.getOrDefault(VOTE, 0); + ProposalDataDb.votersReasons.at(proposalPrefix).set(index - 1, voteReason); + if (voteIndex == APPROVE_) { + ArrayDBUtils.removeArrayItem(ProposalDataDb.approveVoters.at(proposalPrefix), caller); + ProposalDataDb.approvedVotes.at(proposalPrefix).set(approvedVotes.subtract(voterStake)); + } else if (voteIndex == REJECT_) { + ArrayDBUtils.removeArrayItem(ProposalDataDb.rejectVoters.at(proposalPrefix), caller); + ProposalDataDb.rejectedVotes.at(proposalPrefix).set(rejectedVotes.subtract(voterStake)); + } + else{ + ArrayDBUtils.removeArrayItem(abstainVoters.at(proposalPrefix), caller); + ProposalDataDb.abstainedVotes.at(proposalPrefix).set(abstainedVotes.subtract(voterStake)); + } + approvedVotes = (BigInteger) proposalDetails.get(APPROVED_VOTES); + rejectedVotes = (BigInteger) proposalDetails.get(REJECTED_VOTES); + abstainedVotes = (BigInteger) proposalDetails.get(ABSTAINED_VOTES); + + } + if (vote.equals(APPROVE)) { + ProposalDataDb.approveVoters.at(proposalPrefix).add(caller); + votersIndexDb.set(VOTE, APPROVE_); + ProposalDataDb.approvedVotes.at(proposalPrefix).set(approvedVotes.add(voterStake)); + } else if (vote.equals(REJECT)) { + ProposalDataDb.rejectVoters.at(proposalPrefix).add(caller); + votersIndexDb.set(VOTE, REJECT_); + ProposalDataDb.rejectedVotes.at(proposalPrefix).set(rejectedVotes.add(voterStake)); + + } else { + abstainVoters.at(proposalPrefix).add(caller); + votersIndexDb.set(VOTE, ABSTAIN_); + ProposalDataDb.abstainedVotes.at(proposalPrefix).set(abstainedVotes.add(voterStake)); + } + VotedSuccessfully(caller, "Proposal Vote for " + proposalDetails.get(PROJECT_TITLE) + " Successful."); + swapBNUsdToken(); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void vote_proposal(String _ipfs_key, String _vote, String _vote_reason, @Optional boolean _vote_change) { + voteProposal(_ipfs_key, _vote, _vote_reason, _vote_change); + } + + @External + public void migrateAbstainVotes(){ + validateAdmins(); + PeriodController periodController = new PeriodController(); + Context.require(periodController.periodName.get().equals(APPLICATION_PERIOD)); + int size = proposalsKeyList.size(); + for(int i = 0; i < size; i++){ + String proposalPrefix = proposalPrefix(proposalsKeyList.get(i)); + abstainedVotes.at(proposalPrefix).set(BigInteger.ZERO); + } + } + + @External + public void submitProgressReport(ProgressReportAttributes progressReport) { + checkMaintenance(); + update_period(); + PeriodController period = new PeriodController(); + Context.require(period.periodName.get().equals(APPLICATION_PERIOD), + TAG + ": Proposals can only be submitted on Application Period "); + + Address caller = Context.getCaller(); + Context.require(!caller.isContract(), TAG + ": Contract Address not supported."); + + String ipfsHashPrefix = proposalPrefix(progressReport.ipfs_hash); + String tokenFlag = ProposalDataDb.token.at(ipfsHashPrefix).getOrDefault(""); + Context.require(tokenFlag.equals(bnUSD), TAG + ": " + tokenFlag + " Not a supported token."); + + Address contributorAddress = ProposalDataDb.contributorAddress.at(ipfsHashPrefix).get(); + Context.require(caller.equals(contributorAddress), + TAG + ": Sorry, You are not the contributor for this project."); + + String status = ProposalDataDb.status.at(ipfsHashPrefix).get(); + Context.require(List.of(ACTIVE, PAUSED).contains(status), + TAG + ": Sorry, This project is not found on active state."); + + Boolean progressSubmitted = ProposalDataDb.submitProgressReport.at(ipfsHashPrefix).get(); + Context.require(!progressSubmitted, TAG + ": Progress Report is already submitted this cycle."); + + String reportHash = progressReport.report_hash; + Context.require(!_progress_key_exists(reportHash), TAG + ": Report key already exists."); + addNewProgressReportKey(progressReport.ipfs_hash, reportHash); + String reportHashPrefix = progressReportPrefix(reportHash); + addDataToProgressReportDB(progressReport, reportHashPrefix); + int percentageCompleted = progressReport.percentage_completed; + + Context.require(percentageCompleted >= 0 && percentageCompleted <= 100, + TAG + ": Percentage Completed must be between 0 and 100"); + + if (progressReport.budget_adjustment) { + Context.require(getBudgetAdjustmentFeature(), + TAG + ": Budget Adjustment feature is disabled for the moment."); + + Boolean budgetAdjustment = ProposalDataDb.budgetAdjustment.at(ipfsHashPrefix).get(); + Context.require(!budgetAdjustment, + TAG + ": Budget Adjustment Already submitted for this proposal."); + + int projectDuration = ProposalDataDb.projectDuration.at(ipfsHashPrefix).get(); + Context.require(progressReport.additional_month + projectDuration <= MAX_PROJECT_PERIOD, + TAG + ": Maximum period for a project is " + MAX_PROJECT_PERIOD + " months."); + + budgetApprovalsList.add(reportHash); + ProgressReportDataDb.budgetAdjustmentStatus.at(reportHashPrefix).set(PENDING); + ProposalDataDb.budgetAdjustment.at(ipfsHashPrefix).set(true); + } + progressKeyList.add(reportHash); + progressKeyListIndex.set(reportHash, progressKeyList.size() - 1); + + submitProgressReport.at(ipfsHashPrefix).set(true); + waitingProgressReports.add(reportHash); + swapBNUsdToken(); + ProgressReportSubmitted(caller, progressReport.progress_report_title + + " --> Progress Report Submitted Successfully."); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void submit_progress_report(ProgressReportAttributes _progress_report) { + submitProgressReport(_progress_report); + } + + @External + public void voteProgressReport(String ipfsKey, String reportKey, String vote, String voteReason, @Optional String budgetAdjustmentVote, @Optional boolean voteChange) { + if (budgetAdjustmentVote == null) { + budgetAdjustmentVote = ""; + + } + + checkMaintenance(); + update_period(); + PeriodController period = new PeriodController(); + Context.require(period.periodName.get().equals(VOTING_PERIOD), + TAG + ": Progress Reports can be voted only on Voting Period."); + Address caller = Context.getCaller(); + PReps pReps = new PReps(); + Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps), + TAG + ": Voting can only be done by registered P-Reps."); + Context.require(List.of(APPROVE, REJECT).contains(vote), + TAG + ": Vote should be either _approve or _reject"); + + Map progressReportDetails = getProgressReportDetails(reportKey); + String progressReportPrefix = progressReportPrefix(reportKey); + String status = (String) progressReportDetails.get(STATUS); + + ArrayDB
voterList = ProgressReportDataDb.votersList.at(progressReportPrefix); + + if (!voteChange) { + if (ArrayDBUtils.containsInArrayDb(caller, voterList)) { + Context.revert(TAG + ": Already Voted"); + } + } + + if (status.equals(WAITING)) { + BigInteger voterStake = delegationSnapshot.get(String.valueOf(caller)); + BigInteger totalVotes = (BigInteger) progressReportDetails.get(TOTAL_VOTES); + BigInteger approvedVotes = (BigInteger) progressReportDetails.get(APPROVED_VOTES); + BigInteger rejectedVotes = (BigInteger) progressReportDetails.get(REJECTED_VOTES); + Integer totalVoter = (Integer) progressReportDetails.get(TOTAL_VOTERS); + if (totalVoter == 0) { + ProgressReportDataDb.totalVoters.at(progressReportPrefix).set(pReps.validPreps.size()); + } + DictDB votersIndexDb = votersListIndices.at(progressReportPrefix).at(caller); + + if (!voteChange) { + ProgressReportDataDb.totalVotes.at(progressReportPrefix).set(totalVotes.add(voterStake)); + ProgressReportDataDb.votersList.at(progressReportPrefix).add(caller); + votersIndexDb.set(INDEX, ProgressReportDataDb.votersList.at(progressReportPrefix).size()); + ProgressReportDataDb.votersReasons.at(progressReportPrefix).add(voteReason); + } else { + Context.require(votersIndexDb.getOrDefault(CHANGE_VOTE, 0) == 0, + TAG + ": Progress Report Vote change can be done only once."); + votersIndexDb.set(CHANGE_VOTE, 1); + int index = votersIndexDb.getOrDefault(INDEX, 0); + int voteIndex = votersIndexDb.getOrDefault(VOTE, 0); + ProgressReportDataDb.votersReasons.at(progressReportPrefix).set(index - 1, voteReason); + if (voteIndex == APPROVE_) { + ArrayDBUtils.removeArrayItem(ProgressReportDataDb.approveVoters.at(progressReportPrefix), caller); + ProgressReportDataDb.approvedVotes.at(progressReportPrefix).set(approvedVotes.subtract(voterStake)); + } else { + ArrayDBUtils.removeArrayItem(ProgressReportDataDb.rejectVoters.at(progressReportPrefix), caller); + ProgressReportDataDb.rejectedVotes.at(progressReportPrefix).set(rejectedVotes.subtract(voterStake)); + } + + if (ArrayDBUtils.containsInArrayDb(reportKey, budgetApprovalsList)) { + BigInteger budgetApprovedVotes = (BigInteger) progressReportDetails.get(BUDGET_APPROVED_VOTES); + BigInteger budgetRejectedVotes = (BigInteger) progressReportDetails.get(BUDGET_REJECTED_VOTES); + int budgetVoteIndex = budgetVotersListIndices.at(progressReportPrefix).at(caller).getOrDefault(VOTE, 0); + if (budgetVoteIndex == APPROVE_) { + ArrayDBUtils.removeArrayItem(budgetApproveVoters.at(progressReportPrefix), caller); + ProgressReportDataDb.budgetApprovedVotes.at(progressReportPrefix).set(budgetApprovedVotes.subtract(voterStake)); + } else if (budgetVoteIndex == REJECT_) { + ArrayDBUtils.removeArrayItem(budgetRejectVoters.at(progressReportPrefix), caller); + ProgressReportDataDb.budgetRejectedVotes.at(progressReportPrefix).set(budgetRejectedVotes.subtract(voterStake)); + } else { + Context.revert(TAG + ": Choose option " + APPROVE + " or " + REJECT + " for budget adjustment"); + } + + } + approvedVotes = (BigInteger) progressReportDetails.get(APPROVED_VOTES); + rejectedVotes = (BigInteger) progressReportDetails.get(REJECTED_VOTES); + + } + if (vote.equals(APPROVE)) { + ProgressReportDataDb.approveVoters.at(progressReportPrefix).add(caller); + votersIndexDb.set(VOTE, APPROVE_); + ProgressReportDataDb.approvedVotes.at(progressReportPrefix).set(approvedVotes.add(voterStake)); + } else if (vote.equals(REJECT)) { + ProgressReportDataDb.rejectVoters.at(progressReportPrefix).add(caller); + votersIndexDb.set(VOTE, REJECT_); + ProgressReportDataDb.rejectedVotes.at(progressReportPrefix).set(rejectedVotes.add(voterStake)); + + } else { + Context.revert(TAG + ": Choose option " + APPROVE + " or " + REJECT + " for budget adjustment"); + } + + if (ArrayDBUtils.containsInArrayDb(reportKey, budgetApprovalsList)) { + BigInteger budgetApprovedVotes = (BigInteger) progressReportDetails.get(BUDGET_APPROVED_VOTES); + BigInteger budgetRejectedVotes = (BigInteger) progressReportDetails.get(BUDGET_REJECTED_VOTES); + DictDB budgetVoteIndex = budgetVotersListIndices.at(progressReportPrefix).at(caller); + if (budgetAdjustmentVote.equals(APPROVE)) { + ProgressReportDataDb.budgetApproveVoters.at(progressReportPrefix).add(caller); + ProgressReportDataDb.budgetApprovedVotes.at(progressReportPrefix).set(budgetApprovedVotes.add(voterStake)); + budgetVoteIndex.set(VOTE, APPROVE_); + } else if (budgetAdjustmentVote.equals(REJECT)) { + ProgressReportDataDb.budgetRejectVoters.at(progressReportPrefix).add(caller); + ProgressReportDataDb.budgetRejectedVotes.at(progressReportPrefix).set(budgetRejectedVotes.add(voterStake)); + budgetVoteIndex.set(VOTE, REJECT_); + } else { + Context.revert(TAG + ": Choose option " + APPROVE + " or " + REJECT + " for budget adjustment"); + } + } + VotedSuccessfully(caller, "Proposal Vote for " + progressReportDetails.get(PROGRESS_REPORT_TITLE) + " Successful."); + + + swapBNUsdToken(); + } + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void vote_progress_report(String _ipfs_key, String _report_key, String _vote, String _vote_reason, @Optional String _budget_adjustment_vote, @Optional boolean _vote_change) { + voteProgressReport(_ipfs_key, _report_key, _vote, _vote_reason, _budget_adjustment_vote, _vote_change); + } + + @External(readonly = true) + public List getProposalsKeysByStatus(String status) { + Context.require(STATUS_TYPE.contains(status), TAG + ": Not a valid status"); + List proposalStatusList = new ArrayList<>(); + + ArrayDB proposalStatus = this.proposalStatus.get(status); + for (int i = 0; i < proposalStatus.size(); i++) { + proposalStatusList.add(proposalStatus.get(i)); + } + return proposalStatusList; + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public List get_proposals_keys_by_status(String _status) { + return getProposalsKeysByStatus(_status); + } + + @External(readonly = true) + public int checkChangeVote(Address address, String ipfsHash, String proposalType) { + if (proposalType.equals(PROPOSAL)) { + String proposalPrefix = proposalPrefix(ipfsHash); + return ProposalDataDb.votersListIndex.at(proposalPrefix).at(address).get(CHANGE_VOTE); + } else if (proposalType.equals(PROGRESS_REPORTS)) { + String progressReportPrefix = progressReportPrefix(ipfsHash); + return votersListIndices.at(progressReportPrefix).at(address).get(CHANGE_VOTE); + } else { + return 0; + } + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public int check_change_vote(Address _address, String _ipfs_hash, String _proposal_type) { + return checkChangeVote(_address, _ipfs_hash, _proposal_type); + } + + @External(readonly = true) + public Map>> getProjectAmounts() { + List statusList = List.of(PENDING, ACTIVE, PAUSED, COMPLETED, DISQUALIFIED); + BigInteger pendingAmountIcx = BigInteger.ZERO; + BigInteger activeAmountIcx = BigInteger.ZERO; + BigInteger pausedAmountIcx = BigInteger.ZERO; + BigInteger completedAmountIcx = BigInteger.ZERO; + BigInteger disqualifiedAmountIcx = BigInteger.ZERO; + + BigInteger pendingAmountBnusd = BigInteger.ZERO; + BigInteger activeAmountBnusd = BigInteger.ZERO; + BigInteger pausedAmountBnusd = BigInteger.ZERO; + BigInteger completedAmountBnusd = BigInteger.ZERO; + BigInteger disqualifiedAmountBnusd = BigInteger.ZERO; + + for (int statusId = 0; statusId < statusList.size(); statusId++) { + BigInteger amountICX = BigInteger.ZERO; + BigInteger amountBnusd = BigInteger.ZERO; + + List proposalsKeysByStatus = this.get_proposals_keys_by_status(statusList.get(statusId)); + for (String proposalKey : proposalsKeysByStatus) { + Map proposalDetails = getProposalDetails(proposalKey); + BigInteger projectBudget = (BigInteger) proposalDetails.get(TOTAL_BUDGET); + if (proposalDetails.get(TOKEN).equals(ICX)) { + amountICX = amountICX.add(projectBudget); + } else { + amountBnusd = amountBnusd.add(projectBudget); + } + } + + if (statusId == 0) { + pendingAmountIcx = amountICX; + pendingAmountBnusd = amountBnusd; + } else if (statusId == 1) { + activeAmountIcx = amountICX; + activeAmountBnusd = amountBnusd; + } else if (statusId == 2) { + pausedAmountIcx = amountICX; + pausedAmountBnusd = amountBnusd; + } else if (statusId == 3) { + completedAmountIcx = amountICX; + completedAmountBnusd = amountBnusd; + } else { + disqualifiedAmountIcx = amountICX; + disqualifiedAmountBnusd = amountBnusd; + } + + + } + return Map.of(statusList.get(0), Map.of(AMOUNT, Map.of(ICX, pendingAmountIcx, bnUSD, pendingAmountBnusd)), + statusList.get(1), Map.of(AMOUNT, Map.of(ICX, activeAmountIcx, bnUSD, activeAmountBnusd)), + statusList.get(2), Map.of(AMOUNT, Map.of(ICX, pausedAmountIcx, bnUSD, pausedAmountBnusd)), + statusList.get(3), Map.of(AMOUNT, Map.of(ICX, completedAmountIcx, bnUSD, completedAmountBnusd)), + statusList.get(4), Map.of(AMOUNT, Map.of(ICX, disqualifiedAmountIcx, bnUSD, disqualifiedAmountBnusd))); + + + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map>> get_project_amounts() { + return getProjectAmounts(); + } + + @External(readonly = true) + public Map getSponsorsRecord() { + List proposalKeys = new ArrayList<>(); + Map sponsorsDict = new HashMap<>(); + + List activeProposals = get_proposals_keys_by_status(ACTIVE); + proposalKeys.addAll(activeProposals); + List pausedProposals = get_proposals_keys_by_status(PAUSED); + proposalKeys.addAll(pausedProposals); + List completedProposals = get_proposals_keys_by_status(COMPLETED); + proposalKeys.addAll(completedProposals); + + for (String proposal : proposalKeys) { + Map proposalDetails = getProposalDetails(proposal); + String sponsorAddress = proposalDetails.get(SPONSOR_ADDRESS).toString(); + int sponsorValue = 0; + try{ + sponsorValue = sponsorsDict.get(sponsorAddress); + } catch (Exception e){ + sponsorsDict.put(sponsorAddress, 0); + } + + sponsorsDict.put(sponsorAddress, sponsorValue + 1); + } + return sponsorsDict; + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_sponsors_record() { + return getSponsorsRecord(); + } + + @External + public void updatePeriod() { // changed the checking + checkMaintenance(); + BigInteger currentBlock = BigInteger.valueOf(Context.getBlockHeight()); + PeriodController period = new PeriodController(); + BigInteger nextBlock = period.nextBlock.get(); + PReps pReps = new PReps(); + if (currentBlock.compareTo(nextBlock) >= 0) { + if (period.periodName.get().equals(APPLICATION_PERIOD)) { + period.periodName.set(VOTING_PERIOD); + period.periodCount.set(period.periodCount.get() + 1); + period.previousPeriodName.set(APPLICATION_PERIOD); + period.nextBlock.set(nextBlock.add(BLOCKS_DAY_COUNT.multiply(DAY_COUNT))); + updateApplicationResult(); + + period.updatePeriodIndex.set(0); + setPreps(); + snapshotDelegation(); + + int activeProposalCount = pending.size() + waitingProgressReports.size(); + swapCount.set(activeProposalCount + pReps.validPreps.size()); + + } else { + Integer updateIndex = period.updatePeriodIndex.get(); + if (updateIndex == 0) { + period.periodName.set(TRANSITION_PERIOD); + period.previousPeriodName.set(APPLICATION_PERIOD); + period.updatePeriodIndex.set(updateIndex + 1); + updateProposalsResult(); + + PeriodUpdate("Period Update State 1/4. Period Updated to Transition Period. " + + "After all the calculations are completed, " + + "Period will change to " + APPLICATION_PERIOD); + } else if (updateIndex == 1) { + checkProgressReportSubmission(); + period.updatePeriodIndex.set(updateIndex + 1); + PeriodUpdate("Period Update State 2/4. Progress Reports Checks Completed."); + } else if (updateIndex == 2) { + updateProgressReportResult(); + period.updatePeriodIndex.set(updateIndex + 1); + PeriodUpdate("Period Update State 3/4. Progress Reports Calculations Completed."); + } else { + SetterGetter setterGetter = new SetterGetter(); + updateDenylistPreps(); + period.nextBlock.set(nextBlock.add(BLOCKS_DAY_COUNT.multiply(DAY_COUNT))); + period.periodName.set(APPLICATION_PERIOD); + period.previousPeriodName.set(VOTING_PERIOD); + PeriodUpdate("Period Update State 4/4. Period Successfully Updated to Application Period."); + setPreps(); + + int activeProposalCount = active.size() + paused.size(); + swapCount.set(activeProposalCount + activeProposalCount * pReps.validPreps.size()); + callScore(setterGetter.cpfScore.get(), "reset_swap_state"); + + ArrayDBUtils.clearArrayDb(budgetApprovalsList); + ArrayDBUtils.clearArrayDb(activeProposals); + ArrayDBUtils.clearArrayDb(priorityVotedPreps); + + burn(proposalFees.get(), null); + proposalFees.set(BigInteger.ZERO); + } + + } + } + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External + public void update_period() { + updatePeriod(); + } + + private void updateDenylistPreps() { + PReps pReps = new PReps(); + for (int i = 0; i < pReps.inactivePreps.size(); i++) { + Address prep = pReps.inactivePreps.get(i); + ArrayDBUtils.removeArrayItem(pReps.registeredPreps, prep); + pReps.denylist.add(prep); + int count = pReps.prepsDenylistStatus.getOrDefault(prep.toString(), 0) + 1; + pReps.prepsDenylistStatus.set(prep.toString(), Math.min(count, 3)); + PRepPenalty(prep, "P-Rep added to Denylist."); + + } +//Clear all data from the ArrayDB + ArrayDBUtils.clearArrayDb(pReps.inactivePreps); + } + + /*** + Calculate votes for the progress reports and update the status and get the Installment and Sponsor + Reward is the progress report is accepted. + :return: + ***/ + + private void updateProgressReportResult() { + List waiting_progress_reports = arrayDBtoList(this.waitingProgressReports); + PReps pReps = new PReps(); + List
_main_preps_list = arrayDBtoList(pReps.validPreps); + + for (int i = 0; i < waiting_progress_reports.size(); i++) { + String _reports = waiting_progress_reports.get(i); + Map _report_result = getProgressReportDetails(_reports); + + String _ipfs_hash = (String) _report_result.get(IPFS_HASH); + String proposal_prefix = proposalPrefix(_ipfs_hash); + String progressPrefix = progressReportPrefix(_reports); + Map _proposal_details = getProposalDetails(_ipfs_hash); + + submitProgressReport.at(proposal_prefix).set(Boolean.FALSE); + + String _proposal_status = (String) _proposal_details.get(STATUS); + int _approved_reports_count = (int) _proposal_details.get(APPROVED_REPORTS); + Address _sponsor_address = (Address) _proposal_details.get(SPONSOR_ADDRESS); + Address _contributor_address = (Address) _proposal_details.get(CONTRIBUTOR_ADDRESS); + int _completed = (int) _proposal_details.get(PERCENTAGE_COMPLETED); + boolean _budget_adjustment = (boolean) _report_result.get(BUDGET_ADJUSTMENT); + BigInteger _sponsor_deposit_amount = (BigInteger) _proposal_details.get(SPONSOR_DEPOSIT_AMOUNT); + String flag = (String) _proposal_details.get("token"); + + int _approve_voters = (int) _report_result.get(APPROVE_VOTERS); + int _reject_voters = (int) _report_result.get(REJECT_VOTERS); + BigInteger _approved_votes = (BigInteger) _report_result.get(APPROVED_VOTES); + BigInteger _rejected_votes = (BigInteger) _report_result.get(REJECTED_VOTES); + BigInteger _total_votes = (BigInteger) _report_result.get(TOTAL_VOTES); + int _total_voters = (int) _report_result.get(TOTAL_VOTERS); + +// checking which prep(s) did not vote the progress report + checkInactivePreps(ProgressReportDataDb.votersList.at(progressPrefix)); + +// If a progress report have any budget_adjustment, then it checks the budget adjustment first + if (_budget_adjustment) { + updateBudgetAdjustments(_reports); + } + + int _project_duration = projectDuration.at(proposal_prefix).getOrDefault(0); + String updated_status; + double votersRatio = (double) _approve_voters / _total_voters; + if (_total_voters == 0 || _total_votes.equals(BigInteger.ZERO) || _main_preps_list.size() < MINIMUM_PREPS) { + updateProgressReportStatus(_reports, PROGRESS_REPORT_REJECTED); + updated_status = PROGRESS_REPORT_REJECTED; + } else if (votersRatio >= MAJORITY && (_approved_votes.doubleValue() / _total_votes.doubleValue()) >= MAJORITY) { + + updateProgressReportStatus(_reports, APPROVED); + updated_status = APPROVED; + _approved_reports_count += 1; + + if (_approved_reports_count == _project_duration) { + updateProposalStatus(_ipfs_hash, COMPLETED); +// Transfer the Sponsor - Bond back to the Sponsor P - Rep after the project is completed. + this.sponsorBondReturn.at(_sponsor_address.toString()).set(flag, this.sponsorBondReturn.at(_sponsor_address.toString()).getOrDefault(flag, BigInteger.ZERO).add(_sponsor_deposit_amount)); + sponsorDepositStatus.at(proposal_prefix).set(BOND_RETURNED); + SponsorBondReturned(_sponsor_address, + _sponsor_deposit_amount + " " + flag + " returned to sponsor address."); + } else if (_proposal_status.equals(PAUSED)) { + updateProposalStatus(_ipfs_hash, ACTIVE); + } + ProposalDataDb.approvedReports.at(proposal_prefix).set(_approved_reports_count); +// Request CPS Treasury to add some installment amount to the contributor address + callScore(getCpsTreasuryScore(), "send_installment_to_contributor", _ipfs_hash); +// Request CPS Treasury to add some sponsor reward amount to the sponsor address + callScore(getCpsTreasuryScore(), "send_reward_to_sponsor", _ipfs_hash); + + } else { + updateProgressReportStatus(_reports, PROGRESS_REPORT_REJECTED); + updated_status = PROGRESS_REPORT_REJECTED; + } + + if (updated_status.equals(PROGRESS_REPORT_REJECTED)) { + if (_proposal_status.equals(ACTIVE)) { + updateProposalStatus(_ipfs_hash, PAUSED); + } else if (_proposal_status.equals(PAUSED)) { + updateProposalStatus(_ipfs_hash, DISQUALIFIED); + callScore(getCpsTreasuryScore(), "disqualify_project", _ipfs_hash); + + removeContributor(_contributor_address); + removeSponsor(_sponsor_address); + + sponsorDepositStatus.at(proposal_prefix).set(BOND_CANCELLED); + +// Transferring the sponsor bond deposit to CPF after the project being disqualified + disqualifyProject(_sponsor_address, _sponsor_deposit_amount, flag); + } + } + } + } + + /*** + Check if all active and paused proposals submits the progress report + :return: + ***/ + private void checkProgressReportSubmission() { + for (int i = 0; i < activeProposals.size(); i++) { + String _ipfs_hash = activeProposals.get(i); + String proposalPrefix = proposalPrefix(_ipfs_hash); + + Map _proposal_details = getProposalDetails(_ipfs_hash); + String _proposal_status = (String) _proposal_details.get(STATUS); + Address _sponsor_address = (Address) _proposal_details.get(SPONSOR_ADDRESS); + Address _contributor_address = (Address) _proposal_details.get(CONTRIBUTOR_ADDRESS); + String flag = (String) _proposal_details.get("token"); + + if (!ProposalDataDb.submitProgressReport.at(proposalPrefix).getOrDefault(Boolean.FALSE)) { + if (_proposal_status.equals(ACTIVE)) { + updateProposalStatus(_ipfs_hash, PAUSED); + } else if (_proposal_status.equals(PAUSED)) { + updateProposalStatus(_ipfs_hash, DISQUALIFIED); + callScore(getCpsTreasuryScore(), "disqualify_project", _ipfs_hash); + + + removeContributor(_contributor_address); + removeSponsor(_sponsor_address); + + sponsorDepositStatus.at(proposalPrefix).set(BOND_CANCELLED); + BigInteger _sponsor_deposit_amount = (BigInteger) _proposal_details.get(SPONSOR_DEPOSIT_AMOUNT); + +// Transferring the sponsor bond deposit to CPF after the project being disqualified + disqualifyProject(_sponsor_address, _sponsor_deposit_amount, flag); + } + } + } + } + + /*** + Update the budget amount and added month time if the budget adjustment application is approved by majority. + :param _budget_key: report hash of the progress report + :type _budget_key: str + :return: + ***/ + private void updateBudgetAdjustments(String _budget_key) { + Map _report_result = getProgressReportDetails(_budget_key); + String _prefix = progressReportPrefix(_budget_key); + + Map _vote_result = get_budget_adjustment_vote_result(_budget_key); + int _approve_voters = (int) _vote_result.get(APPROVE_VOTERS); + int _total_voters = (int) _vote_result.get(TOTAL_VOTERS); + BigInteger _approved_votes = (BigInteger) _vote_result.get(APPROVED_VOTES); + BigInteger _total_votes = (BigInteger) _vote_result.get(TOTAL_VOTES); + PReps pReps = new PReps(); + double votersRatio = (double) _approve_voters/_total_voters; + if (_total_voters == 0 || _total_votes.equals(BigInteger.ZERO) || pReps.validPreps.size() < MINIMUM_PREPS) { + budgetAdjustmentStatus.at(_prefix).set(REJECTED); + } else if (votersRatio >= MAJORITY && (_approved_votes.doubleValue()/_total_votes.doubleValue()) >= MAJORITY) { + String _ipfs_hash = (String) _report_result.get(IPFS_HASH); + String proposal_prefix = proposalPrefix(_ipfs_hash); + String token_flag = token.at(proposal_prefix).getOrDefault(""); + + int _period_count = projectDuration.at(proposal_prefix).getOrDefault(0); + BigInteger _total_budget = totalBudget.at(proposal_prefix).getOrDefault(BigInteger.ZERO); + int _additional_duration = (int) _report_result.get(ADDITIONAL_DURATION); + BigInteger _additional_budget = (BigInteger) _report_result.get(ADDITIONAL_BUDGET); + + projectDuration.at(proposal_prefix).set(_period_count + _additional_duration); + totalBudget.at(proposal_prefix).set(_total_budget.add(_additional_budget)); + budgetAdjustmentStatus.at(_prefix).set(APPROVED); + + +// After the budget adjustment is approved, Request new added fund to CPF + callScore(get_cpf_treasury_score(), "update_proposal_fund", _ipfs_hash, token_flag, _additional_budget, _additional_duration); + } else { + budgetAdjustmentStatus.at(_prefix).set(REJECTED); + } + } + + private void updateProposalsResult() { + BigInteger distributionAmount = get_remaining_fund().get(bnUSD); + List proposals = sortPriorityProposals(); + PReps pReps = new PReps(); + + for (String proposal : proposals) { + Map proposalDetails = getProposalDetails(proposal); + Address sponsorAddress = (Address) proposalDetails.get(SPONSOR_ADDRESS); + Address contributorAddress = (Address) proposalDetails.get(CONTRIBUTOR_ADDRESS); + BigInteger totalBudget = (BigInteger) proposalDetails.get(TOTAL_BUDGET); + int projectDuration = (int) proposalDetails.get(PROJECT_DURATION); + BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); + int approvedVoters = (int) proposalDetails.get(APPROVE_VOTERS); + BigInteger approvedVotes = (BigInteger) proposalDetails.get(APPROVED_VOTES); + BigInteger totalVotes = (BigInteger) proposalDetails.get(TOTAL_VOTES); + int totalVoters = (int) proposalDetails.get(TOTAL_VOTERS); + String flag = (String) proposalDetails.get(TOKEN); + String updatedStatus; + String proposalPrefix = proposalPrefix(proposal); + + checkInactivePreps(ProposalDataDb.votersList.at(proposalPrefix)); + + double voters_ratio = 0; + if (totalVoters != 0){ + voters_ratio = (double) approvedVoters/totalVoters; + } + if (totalVoters == 0 || totalVotes.equals(BigInteger.ZERO) || pReps.validPreps.size() < MINIMUM_PREPS) { + updateProposalStatus(proposal, REJECTED); + updatedStatus = REJECTED; + } else if ((voters_ratio) >= MAJORITY && + (approvedVotes.doubleValue() / totalVotes.doubleValue()) >= MAJORITY) { + if (totalBudget.multiply(BigInteger.valueOf(102)).divide(BigInteger.valueOf(100)). + compareTo(distributionAmount) < 0) { + updateProposalStatus(proposal, ACTIVE); + updatedStatus = ACTIVE; + sponsors.add(sponsorAddress); + ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).set(BOND_APPROVED); + callScore(get_cpf_treasury_score(), "transfer_proposal_fund_to_cps_treasury", + proposal, projectDuration, sponsorAddress, contributorAddress, flag, totalBudget); + distributionAmount = distributionAmount.subtract(totalBudget); + + } else { + updatedStatus = PENDING; + ProposalDataDb.totalVoters.at(proposalPrefix).set(0); + ProposalDataDb.totalVotes.at(proposalPrefix).set(BigInteger.ZERO); + ProposalDataDb.approvedVotes.at(proposalPrefix).set(BigInteger.ZERO); + ProposalDataDb.rejectedVotes.at(proposalPrefix).set(BigInteger.ZERO); + + ArrayDBUtils.clearArrayDb(ProposalDataDb.rejectVoters.at(proposalPrefix)); + ArrayDBUtils.clearArrayDb(ProposalDataDb.approveVoters.at(proposalPrefix)); + ArrayDBUtils.clearArrayDb(ProposalDataDb.votersList.at(proposalPrefix)); + ArrayDBUtils.clearArrayDb(ProposalDataDb.votersReasons.at(proposalPrefix)); + + for (int i = 0; i < pReps.validPreps.size(); i++) { + Address prep = pReps.validPreps.get(i); + BranchDB> prepVoteChange = ProposalDataDb.votersListIndex.at(proposalPrefix); + prepVoteChange.at(prep).set(VOTE, 0); + prepVoteChange.at(prep).set(INDEX, 0); + prepVoteChange.at(prep).set(CHANGE_VOTE, 0); + } + + } + } else { + updateProposalStatus(proposal, REJECTED); + updatedStatus = REJECTED; + } + + proposalRank.set(proposal, null); + if (updatedStatus.equals(REJECTED)) { + removeContributor(contributorAddress); + sponsorDepositStatus.at(proposal).set(BOND_RETURNED); + BigInteger halfSubmissionFee = BigInteger.valueOf(APPLICATION_FEE /2).multiply(EXA); + Context.transfer(contributorAddress, halfSubmissionFee); + proposalFees.set(proposalFees.get().subtract(halfSubmissionFee)); + + BigInteger sponsorBondAmount = sponsorBondReturn.at(sponsorAddress.toString()).getOrDefault(flag, BigInteger.ZERO); + sponsorBondReturn.at(sponsorAddress.toString()).set(flag, sponsorBondAmount.add(sponsorDepositAmount)); + SponsorBondReturned(sponsorAddress, + sponsorDepositAmount + " returned to sponsor address."); + } + if (proposals.size() > 0) { + checkInactivePreps(priorityVotedPreps); + } + } + } + + private void updateProposalStatus(String proposalHash, String propStatus) { + String proposalPrefix = proposalPrefix(proposalHash); + String currentStatus = ProposalDataDb.status.at(proposalPrefix).get(); + ProposalDataDb.timestamp.at(proposalPrefix).set(BigInteger.valueOf(Context.getBlockHeight())); + ProposalDataDb.status.at(proposalPrefix).set(propStatus); + + ArrayDB proposalStatus = this.proposalStatus.get(currentStatus); + ArrayDBUtils.removeArrayItem(proposalStatus, proposalHash); + this.proposalStatus.get(propStatus).add(proposalHash); + } + + private void updateProgressReportStatus(String progressHash, String progressStatus) { + String progressPrefix = progressReportPrefix(progressHash); + String currentStatus = ProgressReportDataDb.status.at(progressPrefix).get(); + ProposalDataDb.timestamp.at(progressPrefix).set(BigInteger.valueOf(Context.getBlockHeight())); + ProposalDataDb.status.at(progressPrefix).set(progressStatus); + + ArrayDB progressReportStatus = this.progressReportStatus.get(currentStatus); + ArrayDBUtils.removeArrayItem(progressReportStatus, progressHash); + this.progressReportStatus.get(progressStatus).add(progressHash); + } + + private void checkInactivePreps(ArrayDB
prepList) { +// Map voters = new HashMap<>(); +// for (int i = 0; i < prepList.size(); i++) { +// Address prep = (Address) prepList.get(i); +// voters.put(prep, 0); +// } +// PReps pReps = new PReps(); +// List
notVoters = new ArrayList<>(); +// for (int i = 0; i < pReps.validPreps.size(); i++) { +// Address prep = pReps.validPreps.get(i); +// if (voters.containsKey(prep)) { +// notVoters.add(prep); +// } +// } +// for (Address prep : notVoters) { +// if (!ArrayDBUtils.containsInArrayDb(prep, pReps.inactivePreps)) { +// pReps.inactivePreps.add(prep); +// } +// } + PReps pReps = new PReps(); + for(int i = 0; i < pReps.validPreps.size(); i++){ + Address prep = pReps.validPreps.get(i); + if (!containsInArrayDb(prep, prepList) && !containsInArrayDb(prep, pReps.inactivePreps)){ + pReps.inactivePreps.add(prep); + } + } + } + + private Map getProposalDetails(String proposal) { + proposalKeyExists(proposal); + return getDataFromProposalDB(proposalPrefix(proposal)); + } + + private void addNewProgressReportKey(String ipfsHash, String reportHash){ + String prefix = proposalPrefix(ipfsHash); + if (!containsInArrayDb(reportHash, progressReports.at(prefix))) { + progressReports.at(prefix).add(reportHash); + } + } + + @External(readonly = true) + public Map getProposalDetails(String status, @Optional Address walletAddress, @Optional int startIndex, @Optional int endIndex) { + if (endIndex == 0) { + endIndex = 20; + } + if (!STATUS_TYPE.contains(status)) { + return Map.of(MESSAGE, "Not a valid _status."); + } + List proposalsList = new ArrayList<>(); + List proposalKeys = get_proposals_keys_by_status(status); + + if (startIndex < 0) { + startIndex = 0; + } + if ((endIndex - startIndex) > 50) { + return Map.of(MESSAGE, "Page length must not be greater than 50."); + } + + int count = proposalKeys.size(); + if (endIndex > count){ + endIndex = count; + } +// endIndex = ((endIndex > count) ? endIndex : count); + + for (int i = startIndex; i < endIndex; i++) { + String proposalKey = proposalKeys.get(i); + Map proposalDetails = getProposalDetails(proposalKey); + String propStatus = (String) proposalDetails.get(STATUS); + + if (status.equals(SPONSOR_PENDING)) { + Address wallet = (Address) proposalDetails.get(CONTRIBUTOR_ADDRESS); + if (wallet.equals(walletAddress)) { + proposalsList.add(proposalDetails); + } + } else if (propStatus.equals(status)) { + proposalsList.add(proposalDetails); + + } + + } + return Map.of(DATA, proposalsList, COUNT, proposalsList.size()); + + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_proposal_details(String _status, @Optional Address _wallet_address, @Optional int _start_index, @Optional int _end_index) { + return getProposalDetails(_status, _wallet_address, _start_index, _end_index); + } + + @External(readonly = true) + public Map getProposalDetailsByHash(String ipfsKey) { + return getProposalDetails(ipfsKey); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_proposal_details_by_hash(String _ipfs_key) { + return getProposalDetailsByHash(_ipfs_key); + } + + private Map getProgressReportDetails(String progressKey) { + return getDataFromProgressReportDB(progressReportPrefix(progressKey)); + } + + @External(readonly = true) + public Map getProgressReports(String status, @Optional int startIndex, @Optional int endIndex) { + if (endIndex == 0) { + endIndex = 20; + } + if (!PROGRESS_REPORT_STATUS_TYPE.contains(status)) { + return Map.of(MESSAGE, "Not a valid _status."); + } + + List progressReportList = new ArrayList<>(); + ArrayDB progressReportKeys = this.progressReportStatus.get(status); + + if (startIndex < 0) { + startIndex = 0; + } + if ((endIndex - startIndex) > 50) { + return Map.of(MESSAGE, "Page length must not be greater than 50."); + } + int count = progressReportKeys.size(); + + if (endIndex > count){ + endIndex = count; + } + + for (int i = startIndex; i < endIndex; i++) { + String progressReportKey = progressReportKeys.get(i); + Map progressReportDetails = this.getProgressReportDetails(progressReportKey); + String ipfsKey = (String) progressReportDetails.get(IPFS_HASH); + String progressStatus = (String) progressReportDetails.get(STATUS); + + if (progressStatus.equals(status)) { + Map proposalDetails = getProposalDetails(ipfsKey); + String projectTitle = (String) proposalDetails.get(PROJECT_TITLE); + String contributorAddress = proposalDetails.get(CONTRIBUTOR_ADDRESS).toString(); +// TODO: add them to hash map +// progressReportDetails.put(PROJECT_TITLE, projectTitle); +// progressReportDetails.put(CONTRIBUTOR_ADDRESS, contributorAddress); + progressReportList.add(progressReportDetails); + } + } + return Map.of(DATA, progressReportList, COUNT, progressReportList.size()); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_progress_reports(String _status, @Optional int _start_index, @Optional int _end_index) { + return getProgressReports(_status, _start_index, _end_index); + } + + /*** + Returns all the progress reports for a specific project + :param _report_key : project key i.e. progress report ipfs hash + :type _report_key : str + :return : List of all progress report with status + :rtype : dict + ***/ + @External(readonly = true) + public Map getProgressReportsByHash(String reportKey) { + if (!_progress_key_exists(reportKey)) { + return Map.of("message", TAG + ": Not a valid IPFS Hash for Progress Report"); + } + + Map progressDetails = getProgressReportDetails(reportKey); + String _ipfs_hash = (String) progressDetails.get(IPFS_HASH); + return progressDetails; + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_progress_reports_by_hash(String _report_key) { + return getProgressReportsByHash(_report_key); + } + + @External(readonly = true) + public Map getProgressReportsByProposal(String ipfsKey) { + String proposalPrefix = proposalPrefix(ipfsKey); + Map proposalDetails = getProposalDetails(ipfsKey); + String projectTitle = (String) proposalDetails.get(PROJECT_TITLE); + String contributorAddress = proposalDetails.get(CONTRIBUTOR_ADDRESS).toString(); + ArrayDB reportKeys = ProposalDataDb.progressReports.at(proposalPrefix); + + List> progressReportList = new ArrayList<>(); + + for (int i = 0; i < reportKeys.size(); i++) { + Map progressReportDetails = this.getProgressReportDetails(reportKeys.get(i)); + progressReportList.add(progressReportDetails); + } + return Map.of(DATA, progressReportList, COUNT, progressReportList.size()); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_progress_reports_by_proposal(String _ipfs_key) { + return getProgressReportsByProposal(_ipfs_key); + } + + @External(readonly = true) + public Map getSponsorsRequests(String status, Address sponsorAddress, @Optional int startIndex, @Optional int endIndex) { + if (endIndex == 0) { + endIndex = 20; + } + if (!List.of(APPROVED, SPONSOR_PENDING, REJECTED, DISQUALIFIED).contains(status)) { + return Map.of(MESSAGE, "Not a valid _status."); + } + List proposalKeys = new ArrayList<>(); + List sponsorRequests = new ArrayList<>(); + + if (status.equals(APPROVED)) { + List pendingProposals = get_proposals_keys_by_status(PENDING); + proposalKeys.addAll(pendingProposals); + List activeProposals = get_proposals_keys_by_status(ACTIVE); + proposalKeys.addAll(activeProposals); + List pausedProposals = get_proposals_keys_by_status(PAUSED); + proposalKeys.addAll(pausedProposals); + List completedProposals = get_proposals_keys_by_status(COMPLETED); + proposalKeys.addAll(completedProposals); + + + } else { + List proposalKey = get_proposals_keys_by_status(status); + proposalKeys.addAll(proposalKey); + } + if (startIndex < 0) { + startIndex = 0; + } + if ((endIndex - startIndex) > 50) { + return Map.of(MESSAGE, "Page length must not be greater than 50."); + } + int count = proposalKeys.size(); + if (endIndex > count){ + endIndex = count; + } + + BigInteger sponsorAmountICX = BigInteger.ZERO, sponsorAmountBnusd = BigInteger.ZERO; + + for (int i = startIndex; i < endIndex; i++) { + String proposalKey = (String) proposalKeys.get(i); + Map proposalDetails = getProposalDetails(proposalKey); + Address proposalSponsor = (Address) proposalDetails.get(SPONSOR_ADDRESS); + if (proposalSponsor.equals(sponsorAddress)) { + String sponsorDepositStatus = (String) proposalDetails.get(SPONSOR_DEPOSIT_STATUS); + if (sponsorDepositStatus.equals(BOND_APPROVED)) { + String token = (String) proposalDetails.get(TOKEN); + BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); + if (token.equals(ICX)) { + sponsorAmountICX = sponsorAmountICX.add(sponsorDepositAmount); + } else if (token.equals(bnUSD)) { + sponsorAmountBnusd = sponsorAmountBnusd.add(sponsorDepositAmount); + } + sponsorRequests.add(proposalDetails); + } + } + } + return Map.of(DATA, sponsorRequests, COUNT, sponsorRequests.size(), + SPONSOR_DEPOSIT_AMOUNT, Map.of(ICX, sponsorAmountICX, bnUSD, sponsorAmountBnusd)); + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public Map get_sponsors_requests(String _status, Address _sponsor_address, @Optional int _start_index, @Optional int _end_index) { + return getSponsorsRequests(_status, _sponsor_address, _start_index, _end_index); + } + + /*** + Returns remaining projects and progress reports to vote on the current voting period + :param _project_type: "proposal" or "progress_report" which type, remaining votes need to be checked + :type _project_type: str + :param _wallet_address: Wallet Address of the P-Rep + :type _wallet_address: str + :return: list of details of proposal or progress report what they need to vote on the same voting period + ***/ +// @External(readonly = true) +// public List> get_remaining_project(String _project_type, Address _wallet_address) { +// +// List> _remaining_proposals = new ArrayList<>(); +// List> _remaining_progress_report = new ArrayList<>(); +// if (_project_type.equals(PROPOSAL)) { +// List _proposal_keys = get_proposals_keys_by_status(PENDING); +// +// for (String _ipfs_key: _proposal_keys) { +// String prefix = proposalPrefix(_ipfs_key); +// +// if (!containsInArrayDb(_wallet_address, ProposalDataDb.votersList.at(prefix))){ +// Map _proposal_details = getProposalDetails(_ipfs_key); +// _remaining_proposals.add(_proposal_details); +// } +// } +// return _remaining_proposals; +// } +// +// if (_project_type.equals(PROGRESS_REPORTS)) { +// for (int i = 0; i < waitingProgressReports.size(); i++) { +// prefix = self.progress_report_prefix(_report_key) +// _voters_list = self.progress_reports[prefix].voters_list +// +// if (!containsInArrayDb(_wallet_address, ProgressReportDataDb.votersList.at(pre))) +// _progress_reports_details = self._get_progress_reports_details(_report_key) +// _ipfs_hash = _progress_reports_details.get(IPFS_HASH) +// _progress_reports_details[PROJECT_TITLE] = self._get_proposal_details(_ipfs_hash). +// +// get(PROJECT_TITLE) +// _remaining_progress_report.append(_progress_reports_details) +// } +// +// return _remaining_progress_report +// } +//} + + /*** + Get vote results by proposal + :param _ipfs_key : proposal ipfs key + :type _ipfs_key : str + :return: Vote status of given _ipfs_key + :rtype : dict + ***/ + @External(readonly = true) + public Map getVoteResult(String ipfsKey){ + Map _proposal_details = getProposalDetails(ipfsKey); + String prefix = proposalPrefix(ipfsKey); + + ArrayDB
_voters_list = ProposalDataDb.votersList.at(prefix); + ArrayDB
_approved_voters_list = ProposalDataDb.approveVoters.at(prefix); + ArrayDB
_rejected_voters_list = ProposalDataDb.rejectVoters.at(prefix); + + List> _vote_status = new ArrayList<>(); + String vote; + for (int i = 0; i < _voters_list.size(); i++) { + Address voter = _voters_list.get(i); + if (containsInArrayDb(voter, _approved_voters_list)) { + vote = APPROVE; + } + else if (containsInArrayDb(voter, _rejected_voters_list)) { + vote = REJECT; + } + else { + vote = ABSTAIN; + } + String reason = ProposalDataDb.votersReasons.at(prefix).get(i); + + Map _voters = Map.of(ADDRESS, voter, + PREP_NAME, getPrepName(voter), + VOTE_REASON, reason, + VOTE, vote); + _vote_status.add(_voters); + } + + return Map.of(DATA, _vote_status, APPROVE_VOTERS, _proposal_details.get(APPROVE_VOTERS), + REJECT_VOTERS, _proposal_details.get(REJECT_VOTERS), + TOTAL_VOTERS, _proposal_details.get(TOTAL_VOTERS), + APPROVED_VOTES, _proposal_details.get(APPROVED_VOTES), + REJECTED_VOTES, _proposal_details.get(REJECTED_VOTES), + TOTAL_VOTES, _proposal_details.get(TOTAL_VOTES)); + } + + @Override + @External(readonly = true) + @Deprecated(since = "JAVA translation", forRemoval = true) + public Map get_vote_result(String _ipfs_key){ + return getVoteResult(_ipfs_key); + } + + /*** + Get vote results by progress report + :param reportKey : progress report ipfs key + :type reportKey : str + :return: Vote status of given reportKey + :rtype : dict + ***/ + @External(readonly = true) + public Map getProgressReportResult(String reportKey){ + Map _proposal_details = getProgressReportDetails(reportKey); + String prefix = progressReportPrefix(reportKey); + + + List
_voters_list = arrayDBtoList(ProgressReportDataDb.votersList.at(prefix)); + List
_approved_voters_list = arrayDBtoList(ProgressReportDataDb.approveVoters.at(prefix)); + List
_rejected_voters_list = arrayDBtoList(ProgressReportDataDb.rejectVoters.at(prefix)); + List> _vote_status = new ArrayList<>(); + String vote; +// Differentiating the P-Rep(s) votes according to their votes + for (int i = 0; i < _voters_list.size(); i++) { + Address voter = _voters_list.get(i); + if (containsInList(voter, _approved_voters_list)){ + vote = APPROVE; + } + else if(containsInList(voter, _rejected_voters_list)){ + vote = REJECT; + } + else{ + vote = "not voted"; + } + String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); + + Map _voters = Map.of(ADDRESS, voter, + PREP_NAME, getPrepName(voter), + VOTE_REASON, reason, + VOTE, vote); + _vote_status.add(_voters); + } + + return Map.of(DATA, _vote_status, APPROVE_VOTERS, _approved_voters_list.size(), + REJECT_VOTERS,_rejected_voters_list.size(), + TOTAL_VOTERS, _proposal_details.get(TOTAL_VOTERS), + APPROVED_VOTES, _proposal_details.get(APPROVED_VOTES), + REJECTED_VOTES, _proposal_details.get(REJECTED_VOTES), + TOTAL_VOTES, _proposal_details.get(TOTAL_VOTES)); + } + + @Override + @External(readonly = true) + @Deprecated(since = "JAVA translation", forRemoval = true) + public Map get_progress_report_result(String _report_key){ + return getProgressReportResult(_report_key); + } + + /*** + Get budget adjustment vote results + :param _report_key : progress report ipfs key + :type _report_key : str + :return: Vote status of given _report_key + :rtype : dict + ***/ + + @External(readonly = true) + public Map getBudgetAdjustmentVoteResult(String reportKey){ + Map _proposal_details = getProgressReportDetails(reportKey); + String prefix = progressReportPrefix(reportKey); + + List
_voters_list = arrayDBtoList(ProgressReportDataDb.votersList.at(prefix)); + List
_approved_voters_list = arrayDBtoList(budgetApproveVoters.at(prefix)); + List
_rejected_voters_list = arrayDBtoList(budgetRejectVoters.at(prefix)); + List> _vote_status = new ArrayList<>(); + String vote; + for (int i = 0; i < _voters_list.size(); i++) { + Address voter = _voters_list.get(i); + if (containsInList(voter, _approved_voters_list)) { + vote = APPROVE; + } + else if (containsInList(voter, _rejected_voters_list)) { + vote = REJECT; + } + else { + vote = "not voted"; + } + String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); + Map _voters = Map.of( + ADDRESS, voter, + PREP_NAME, getPrepName(voter), + VOTE_REASON, reason, + VOTE, vote); + _vote_status.add(_voters); + } + + return Map.of(DATA, _vote_status, APPROVE_VOTERS, _proposal_details.get(BUDGET_APPROVE_VOTERS), + REJECT_VOTERS, _proposal_details.get(BUDGET_REJECT_VOTERS), + TOTAL_VOTERS, _proposal_details.get(TOTAL_VOTERS), + APPROVED_VOTES, _proposal_details.get(BUDGET_APPROVED_VOTES), + REJECTED_VOTES, _proposal_details.get(BUDGET_REJECTED_VOTES), + TOTAL_VOTES, _proposal_details.get(TOTAL_VOTES)); + } + + @Override + @External(readonly = true) + @Deprecated(since = "JAVA translation", forRemoval = true) + public Map get_budget_adjustment_vote_result(String _report_key){ + return getBudgetAdjustmentVoteResult(_report_key); + } + + + private void snapshotDelegation() { + BigInteger maxDelegation = BigInteger.ZERO; + PReps pReps = new PReps(); + for (int i = 0; i < pReps.validPreps.size(); i++) { + Address prep = pReps.validPreps.get(i); + BigInteger stake = getStake(prep); + delegationSnapshot.set(prep.toString(), stake); + if (stake.compareTo(maxDelegation) > 0) { + maxDelegation = stake; + } + } + this.maxDelegation.set(maxDelegation); + } + + private void updateApplicationResult() { + PReps pReps = new PReps(); + PeriodController period = new PeriodController(); + if (pReps.validPreps.size() < MINIMUM_PREPS) { + period.periodName.set(APPLICATION_PERIOD); + PeriodUpdate("Period Updated back to Application Period due to less Registered P-Reps Count"); + + } else if (get_proposals_keys_by_status(PENDING).size() == 0 && this.progressReportStatus.get(WAITING).size() == 0 && activeProposals.size() + paused.size() == 0) { + createActiveProposalDb(); + checkProgressReportSubmission(); + period.periodName.set(APPLICATION_PERIOD); + PeriodUpdate("Period Updated back to Application Period due not enough " + + "Voting Proposals or Progress Reports."); + } else if (pending.size() == 0 && waitingProgressReports.size() == 0 && activeProposals.size() + paused.size() > 0) { + createActiveProposalDb(); + checkProgressReportSubmission(); + period.periodName.set(APPLICATION_PERIOD); + PeriodUpdate("Period Updated back to Application Period due not enough " + + "Voting Proposals or Progress Reports."); + + } else { + createActiveProposalDb(); + PeriodUpdate("Period Updated to Voting Period"); + } + } + + private void createActiveProposalDb() { + for (int i = 0; i < active.size(); i++) { + String proposal = active.get(i); + if (!ArrayDBUtils.containsInArrayDb(proposal, activeProposals)) { + activeProposals.add(proposal); + } + } + for (int i = 0; i < paused.size(); i++) { + String proposal = paused.get(i); + if (!ArrayDBUtils.containsInArrayDb(proposal, activeProposals)) { + activeProposals.add(proposal); + } + } + } + + private void payPrepPenalty(Address from, BigInteger _value) { + checkMaintenance(); + update_period(); + PReps pReps = new PReps(); + PeriodController period = new PeriodController(); + Context.require(period.periodName.get().equals(APPLICATION_PERIOD), + TAG + " Penalty can only be paid on Application Period"); + Context.require(ArrayDBUtils.containsInArrayDb(from, pReps.denylist), + TAG + " " + from + " not in denylist."); + + BigInteger penaltyAmount = getPenaltyAmount(from); + Context.require(penaltyAmount.equals(_value), + "Please pay Penalty amount of" + penaltyAmount + " to register as a P-Rep."); + SetterGetter setterGetter = new SetterGetter(); + ArrayDBUtils.removeArrayItem(pReps.denylist, from); + pReps.registeredPreps.add(from); + pReps.validPreps.add(from); + burn(_value, setterGetter.balancedDollar.get()); + PRepPenalty(from, _value + " bnUSD Penalty Received. P-Rep removed from Denylist."); + + } + + @Override + @External + public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { + Context.require(Context.getCaller().equals(get_bnUSD_score()), TAG + " Only bnUSD token accepted."); + + String unpacked_data = new String(_data); + JsonObject transferData = Json.parse(unpacked_data).asObject(); + String methodName = transferData.get("method").asString(); + JsonObject paramsName = transferData.get("params").asObject(); + + if (methodName.equals("sponsor_vote")) { + String ipfsKey = paramsName.get(IPFS_HASH).asString(); + String vote = paramsName.get(VOTE).asString(); + String voteReason = paramsName.get(VOTE_REASON).asString(); + sponsorVote(ipfsKey, vote, voteReason, _from, _value); + } else if (methodName.equals("pay_prep_penalty")) { + payPrepPenalty(_from, _value); + + } else { + Context.revert(TAG + " Not supported method. Token transfer fails."); + } + + + } + + private void sponsorVote(String ipfsKey, String vote, String voteReason, Address from, BigInteger value) { + checkMaintenance(); + update_period(); + PeriodController period = new PeriodController(); + Context.require(period.periodName.get().equals(APPLICATION_PERIOD), + TAG + " Sponsor Vote can only be done on Application Period"); + PReps pReps = new PReps(); + Context.require(ArrayDBUtils.containsInArrayDb(from, pReps.validPreps), TAG + ": Not a P-Rep"); + + swapBNUsdToken(); + Map proposalDetails = getProposalDetails(ipfsKey); + String status = (String) proposalDetails.get(STATUS); + Address sponsorAddress = (Address) proposalDetails.get(SPONSOR_ADDRESS); + Address contributorAddress = (Address) proposalDetails.get(CONTRIBUTOR_ADDRESS); + String token = (String) proposalDetails.get(TOKEN); + + Context.require(from.equals(sponsorAddress), TAG + ": Not a valid sponsor"); + Context.require(List.of(ACCEPT, REJECT).contains(vote), TAG + ": Not valid vote"); + + if (vote.equals(ACCEPT)) { + Context.require(status.equals(SPONSOR_PENDING), + TAG + ": Sponsor can be only approve sponsorship for Pending proposals."); + Context.require(token.equals(bnUSD), TAG + ": " + token + " Not a supported token."); + + BigInteger projectBudget = (BigInteger) proposalDetails.get(TOTAL_BUDGET); + + Context.require(value.equals(projectBudget.divide(BigInteger.TEN)), + TAG + ": Deposit 10% of the total budget of the project."); + + updateProposalStatus(ipfsKey, PENDING); + String proposalPrefix = proposalPrefix(ipfsKey); + sponsorDepositAmount.at(proposalPrefix).set(value); + sponsoredTimestamp.at(proposalPrefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); + sponsorDepositStatus.at(proposalPrefix).set(BOND_RECEIVED); + sponsorVoteReason.at(proposalPrefix).set(voteReason); + + SponsorBondReceived(from, "Sponsor Bond " + value + " " + token + " Received."); + } else { + removeContributor(contributorAddress); + updateProposalStatus(ipfsKey, REJECTED); + BigInteger halfSubmissionFee = BigInteger.valueOf(APPLICATION_FEE / 2).multiply(EXA); + Context.transfer(contributorAddress, halfSubmissionFee); + proposalFees.set(proposalFees.get().subtract(halfSubmissionFee)); + SponsorBondRejected(from, + "Sponsor Bond Rejected for project " + proposalDetails.get(PROJECT_TITLE)); + + } + } + + @External + public void removeDenylistPreps() { + validateAdmins(); + PReps pReps = new PReps(); + for (int i = 0; i < pReps.denylist.size(); i++) { + Address prep = pReps.denylist.pop(); + pReps.prepsDenylistStatus.set(prep.toString(), 0); + } + } + + @Override + @External + @Deprecated(since = "JAVA translation", forRemoval = true) + public void remove_denylist_preps() { + removeDenylistPreps(); + } + + @External + public void claimSponsorBond() { + Address caller = Context.getCaller(); + DictDB userAmounts = sponsorBondReturn.at(caller.toString()); + BigInteger amountIcx = userAmounts.getOrDefault(ICX, BigInteger.ZERO); + BigInteger amountBNUsd = userAmounts.getOrDefault(bnUSD, BigInteger.ZERO); + + if (amountIcx.compareTo(BigInteger.ZERO) > 0) { + userAmounts.set(ICX, BigInteger.ZERO); + Context.transfer(caller, amountIcx); + SponsorBondClaimed(caller, amountIcx, amountIcx + " " + ICX + " withdrawn to " + caller); + + } else if (amountBNUsd.compareTo(BigInteger.ZERO) > 0) { + userAmounts.set(bnUSD, BigInteger.ZERO); + callScore(get_bnUSD_score(), "transfer", caller, amountBNUsd); + SponsorBondClaimed(caller, amountIcx, amountBNUsd + " " + bnUSD + " withdrawn to " + caller); + } else { + Context.revert(TAG + " Claim Reward Fails. Available Amounts are " + amountIcx + " " + ICX + " and" + amountBNUsd + " " + bnUSD); + } + } + + @Override + @External + @Deprecated(since = "JAVA translation", forRemoval = true) + public void claim_sponsor_bond() { + claimSponsorBond(); + } + + private void swapBNUsdToken() { + BigInteger sbh = swapBlockHeight.getOrDefault(BigInteger.ZERO); + BigInteger currentBlock = BigInteger.valueOf(Context.getBlockHeight()); + if (sbh.compareTo(currentBlock) < 0) { + swapBlockHeight.set(currentBlock.add(SWAP_BLOCK_DIFF)); + callScore(get_cpf_treasury_score(), "swap_tokens", swapCount.getOrDefault(0)); + } + } + + @External + public void setSwapCount(int value) { + validateAdmins(); + if (value > 0) { + swapCount.set(value); + } else { + Context.revert(value + " must be greater than 0"); + } + } + + @Override + @External + @Deprecated(since = "JAVA translation", forRemoval = true) + public void set_swap_count(int value) { + setSwapCount(value); + } + + @External(readonly = true) + public int getSwapCount(){ + return swapCount.get(); + } + + @External + public void updateNextBlock(int blockCount) { + validateAdmins(); + PeriodController period = new PeriodController(); + period.nextBlock.set(BigInteger.valueOf(Context.getBlockHeight() + blockCount)); + } + + @Override + @External + @Deprecated(since = "JAVA translation", forRemoval = true) + public void update_next_block(int blockCount) { + updateNextBlock(blockCount); + } + + private void disqualifyProject(Address sponsorAddress, BigInteger sponsorDepositAmount, String flag) { + Context.require(flag.equals(bnUSD), TAG + " Not supported Token"); + JsonObject disqualifyProject = new JsonObject(); + disqualifyProject.add("method", "burn_amount"); + JsonObject params = new JsonObject(); + params.add(SPONSOR_ADDRESS, sponsorAddress.toString()); + disqualifyProject.add("params", params); + Address cpfScore = get_cpf_treasury_score(); + callScore(get_bnUSD_score(), "transfer", cpfScore, + sponsorDepositAmount, disqualifyProject.toString().getBytes()); + SponsorBondReturned(cpfScore, "Project Disqualified. " + sponsorDepositAmount + " " + flag + + " returned to CPF Treasury Address."); + + + } + + @External(readonly = true) + public List> getActiveProposals() { + List proposalKeys = new ArrayList<>(); + List> activeProposalsMap = new ArrayList<>(); + + List activeProposals = get_proposals_keys_by_status(ACTIVE); + proposalKeys.addAll(activeProposals); + List pausedProposals = get_proposals_keys_by_status(PAUSED); + proposalKeys.addAll(pausedProposals); + + for (String proposal : proposalKeys) { + Map proposalDetails = getProposalDetails(proposal); + activeProposalsMap.add(proposalDetails); + + } + return activeProposalsMap; + } + + @Override + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public List> get_active_proposals() { + return getActiveProposals(); + } + + /*** + Returns a dict of proposals of provided status + :param walletAddress : user Signing in + :type walletAddress : 'iconservice.base.address' + :return: List of all proposals_details + ***/ + @External(readonly =true) + public Map getProposalDetailByWallet(Address walletAddress) { + List> _proposals_list = new ArrayList<>(); + + for (int i = 0; i < proposalsKeyList.size(); i++) { + Map _proposal_details = getProposalDetails(proposalsKeyList.get(i)); + if (_proposal_details.get(CONTRIBUTOR_ADDRESS).equals(walletAddress)) { + _proposals_list.add(_proposal_details); + } + } + return Map.of(DATA, _proposals_list, COUNT, _proposals_list.size()); + } + + @Override + @External(readonly =true) + public Map get_proposal_detail_by_wallet(Address _wallet_address) { + return getProposalDetailByWallet(_wallet_address); + } + + @Override + @External + public List> getProposalsHistory() { + List proposalKeys = new ArrayList<>(); + List> activeProposalsMap = new ArrayList<>(); + + List completedProjects = get_proposals_keys_by_status(COMPLETED); + proposalKeys.addAll(completedProjects); + List rejectedProposals = get_proposals_keys_by_status(REJECTED); + proposalKeys.addAll(rejectedProposals); + List disqualifiedProjects = get_proposals_keys_by_status(DISQUALIFIED); + proposalKeys.addAll(disqualifiedProjects); + + for (String proposal : proposalKeys) { + Map proposalDetails = getProposalDetails(proposal); + activeProposalsMap.add(proposalDetails); + } + return activeProposalsMap; + } + + + // EventLogs + @Override + @EventLog(indexed = 1) + public void ProposalSubmitted(Address _sender_address, String note) { + } + + @Override + @EventLog(indexed = 1) + public void ProgressReportSubmitted(Address _sender_address, String _project_title) { + } + + @Override + @EventLog(indexed = 1) + public void SponsorBondReceived(Address _sender_address, String _notes) { + } + + @Override + @EventLog(indexed = 1) + public void SponsorBondRejected(Address _sender_address, String _notes) { + } + + @Override + @EventLog(indexed = 1) + public void VotedSuccessfully(Address _sender_address, String _notes) { + } + + @Override + @EventLog(indexed = 1) + public void PRepPenalty(Address _prep_address, String _notes) { + } + + @Override + @EventLog(indexed = 1) + public void UnRegisterPRep(Address _sender_address, String _notes) { + } + + @Override + @EventLog(indexed = 1) + public void RegisterPRep(Address _sender_address, String _notes) { + } + + @Override + @EventLog(indexed = 1) + public void SponsorBondReturned(Address _sender_address, String _notes) { + } + + @Override + @EventLog(indexed = 1) + public void PeriodUpdate(String _notes) { + } + + @Override + @EventLog(indexed = 1) + public void SponsorBondClaimed(Address _receiver_address, BigInteger _fund, String note) { + } + + @Override + @EventLog(indexed = 1) + public void PriorityVote(Address _address, String note) { + } + + public T callScore(Class t, Address address, String method, Object... params) { + return Context.call(t, address, method, params); + } + + public void callScore(Address address, String method, Object... params) { + Context.call(address, method, params); + } + + public void callScore(BigInteger amount, Address address, String method, Object... params) { + Context.call(amount, address, method, params); + } + + private void logger(String msg){ + Context.println(msg); + } + + + /****************************************************************************************************************** + To be removed in production + ****************************************************************************************************************/ + +// @External +// public void register_prep_(Address caller) { +// validateAdmins(); +// checkMaintenance(); +// update_period(); +// List
prepList = getPrepsAddress(); +// PReps pReps = new PReps(); +// +// Context.require(prepList.contains(caller), +// TAG + ": Not a P-Rep."); +// Context.require(!ArrayDBUtils.containsInArrayDb(caller, pReps.registeredPreps), +// TAG + ": P-Rep is already registered."); +// Context.require(!ArrayDBUtils.containsInArrayDb(caller, pReps.denylist), +// TAG + ": You are in denylist. To register, You've to pay Penalty."); +// +// if (ArrayDBUtils.containsInArrayDb(caller, pReps.unregisteredPreps)) { +// ArrayDBUtils.removeArrayItem(pReps.unregisteredPreps, caller); +// } +// pReps.registeredPreps.add(caller); +// RegisterPRep(caller, "P-Rep Registered."); +// PeriodController period = new PeriodController(); +// pReps.validPreps.add(caller); +// +// } +// +// @External +// public void payPrepPenalty_(Address from, BigInteger _value) { +// validateAdmins(); +// checkMaintenance(); +// update_period(); +// PReps pReps = new PReps(); +// Context.require(ArrayDBUtils.containsInArrayDb(from, pReps.denylist), +// TAG + " " + from + " not in denylist."); +// ArrayDBUtils.removeArrayItem(pReps.denylist, from); +// pReps.registeredPreps.add(from); +// pReps.validPreps.add(from); +// PRepPenalty(from, _value + " bnUSD Penalty Received. P-Rep removed from Denylist."); +// +// } +// +// @External +// public void setProposalFees(BigInteger value){ +// validateAdmins(); +// proposalFees.set(value); +// } +// +// @External(readonly = true) +// public Map getProposalFees(){ +// return Map.of( +// "proposalFees", proposalFees.get(), +// "cpsBalance", Context.getBalance(Context.getAddress()) +// ); +// } + +} \ No newline at end of file diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/PReps.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/PReps.java new file mode 100644 index 00000000..64ed58bb --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/PReps.java @@ -0,0 +1,28 @@ +package community.icon.cps.score.cpscore; + +import score.Address; +import score.ArrayDB; +import score.Context; +import score.DictDB; + +import java.math.BigInteger; + +import static community.icon.cps.score.cpscore.utils.Constants.DENYLIST; +import static community.icon.cps.score.cpscore.utils.Constants.INACTIVE_PREPS; +import static community.icon.cps.score.cpscore.utils.Constants.MAIN_PREPS; +import static community.icon.cps.score.cpscore.utils.Constants.PENALTY_AMOUNT; +import static community.icon.cps.score.cpscore.utils.Constants.PREPS_DENYLIST_STATUS; +import static community.icon.cps.score.cpscore.utils.Constants.REGISTERED_PREPS; +import static community.icon.cps.score.cpscore.utils.Constants.UNREGISTERED_PREPS; + +public class PReps { + public final ArrayDB
validPreps = Context.newArrayDB(MAIN_PREPS, Address.class); + public final ArrayDB
unregisteredPreps = Context.newArrayDB(UNREGISTERED_PREPS, Address.class); + public final ArrayDB
registeredPreps = Context.newArrayDB(REGISTERED_PREPS, Address.class); + public final ArrayDB
inactivePreps = Context.newArrayDB(INACTIVE_PREPS, Address.class); + public final ArrayDB
denylist = Context.newArrayDB(DENYLIST, Address.class); + + public final ArrayDB penaltyAmount = Context.newArrayDB(PENALTY_AMOUNT, BigInteger.class); + + public final DictDB prepsDenylistStatus = Context.newDictDB(PREPS_DENYLIST_STATUS, Integer.class); +} diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/PeriodController.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/PeriodController.java new file mode 100644 index 00000000..21003a24 --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/PeriodController.java @@ -0,0 +1,17 @@ +package community.icon.cps.score.cpscore; + +import score.Context; +import score.VarDB; + +import java.math.BigInteger; + +import static community.icon.cps.score.cpscore.utils.Constants.*; + +public class PeriodController { + public final VarDB initialBlock = Context.newVarDB(INITIAL_BLOCK, BigInteger.class); + public final VarDB periodName = Context.newVarDB(PERIOD_NAME, String.class); + public final VarDB previousPeriodName = Context.newVarDB(PREVIOUS_PERIOD_NAME, String.class); + public final VarDB nextBlock = Context.newVarDB(NEXTBLOCK, BigInteger.class); + public final VarDB updatePeriodIndex = Context.newVarDB(UPDATE_PERIOD_INDEX, Integer.class); + public final VarDB periodCount = Context.newVarDB(PERIOD_COUNT, Integer.class); +} diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/SetterGetter.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/SetterGetter.java new file mode 100644 index 00000000..7dde67c8 --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/SetterGetter.java @@ -0,0 +1,22 @@ +package community.icon.cps.score.cpscore; + +import score.Address; +import score.Context; +import score.VarDB; +import score.annotation.External; + +import java.math.BigInteger; + +//import static community.icon.cps.score.cpscore.utils.Checkers.validateAdminScore; +//import static community.icon.cps.score.cpscore.utils.Checkers.validateAdmins; +import static community.icon.cps.score.cpscore.utils.Constants.*; + +public class SetterGetter { + public final VarDB
cpsTreasuryScore = Context.newVarDB(CPS_TREASURY_SCORE, Address.class); + public final VarDB
cpfScore = Context.newVarDB(CPF_SCORE, Address.class); + public final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); + public final VarDB budgetAdjustment = Context.newVarDB(BUDGETADJUSTMENT, Boolean.class); + public final VarDB maintenance = Context.newVarDB(MAINTENANCE, Boolean.class); + + +} diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java new file mode 100644 index 00000000..f17eb552 --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java @@ -0,0 +1,91 @@ +package community.icon.cps.score.cpscore.db; + +import score.*; + +import java.math.BigInteger; +import scorex.util.HashMap; +import java.util.Map; + +import static community.icon.cps.score.cpscore.utils.Constants.*; +import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; +import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; + +public class ProgressReportDataDb { + private static final BranchDB> ipfsHash = Context.newBranchDB(IPFS_HASH, String.class); + private static final BranchDB> reportHash = Context.newBranchDB(REPORT_HASH, String.class); + private static final BranchDB> progressReportTitle = Context.newBranchDB(PROGRESS_REPORT_TITLE, String.class); + private static final BranchDB> timestamp = Context.newBranchDB(TIMESTAMP, BigInteger.class); + public static final BranchDB> status = Context.newBranchDB(STATUS, String.class); + private static final BranchDB> txHash = Context.newBranchDB(TX_HASH, String.class); + private static final BranchDB> budgetAdjustment = Context.newBranchDB(BUDGET_ADJUSTMENT, Boolean.class); + private static final BranchDB> additionalBudget = Context.newBranchDB(ADDITIONAL_BUDGET, BigInteger.class); + private static final BranchDB> additionalMonth = Context.newBranchDB(ADDITIONAL_DURATION, Integer.class); + private static final BranchDB> percentageCompleted = Context.newBranchDB(PERCENTAGE_COMPLETED, Integer.class); + + public static final BranchDB> votersReasons = Context.newBranchDB(VOTERS_REASON, String.class); + public static final BranchDB> totalVotes = Context.newBranchDB(TOTAL_VOTES, BigInteger.class); + public static final BranchDB> approvedVotes = Context.newBranchDB(APPROVED_VOTES, BigInteger.class); + public static final BranchDB> rejectedVotes = Context.newBranchDB(REJECTED_VOTES, BigInteger.class); + public static final BranchDB> votersList = Context.newBranchDB(VOTERS_LIST, Address.class); + public static final BranchDB> approveVoters = Context.newBranchDB(APPROVE_VOTERS, Address.class); + public static final BranchDB> rejectVoters = Context.newBranchDB(REJECT_VOTERS, Address.class); + public static final BranchDB> totalVoters = Context.newBranchDB(TOTAL_VOTERS, Integer.class); + + public static final BranchDB>> votersListIndices = Context.newBranchDB(VOTERS_LIST_INDEXES, Integer.class); + public static final BranchDB> budgetApprovedVotes = Context.newBranchDB(BUDGET_APPROVED_VOTES, BigInteger.class); + public static final BranchDB> budgetRejectedVotes = Context.newBranchDB(BUDGET_REJECTED_VOTES, BigInteger.class); + public static final BranchDB> budgetApproveVoters = Context.newBranchDB(BUDGET_APPROVE_VOTERS, Address.class); + public static final BranchDB> budgetRejectVoters = Context.newBranchDB(BUDGET_REJECT_VOTERS, Address.class); + public static final BranchDB> budgetAdjustmentStatus = Context.newBranchDB(BUDGET_ADJUSTMENT_STATUS, String.class); + public static final BranchDB> ipfsLink = Context.newBranchDB(IPFS_LINK, String.class); + public static final BranchDB>> budgetVotersListIndices = Context.newBranchDB(BUDGET_VOTERS_LIST_INDICES, Integer.class); + + public static void addDataToProgressReportDB(ProgressReportAttributes progressData, String prefix) { + ipfsHash.at(prefix).set(progressData.ipfs_hash); + reportHash.at(prefix).set(progressData.report_hash); + progressReportTitle.at(prefix).set(progressData.progress_report_title); + timestamp.at(prefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); + additionalBudget.at(prefix).set(progressData.additional_budget.multiply(EXA)); + additionalMonth.at(prefix).set(progressData.additional_month); + percentageCompleted.at(prefix).set(progressData.percentage_completed); + status.at(prefix).set(WAITING); + txHash.at(prefix).set(recordTxHash(Context.getTransactionHash())); + budgetAdjustment.at(prefix).set(progressData.budget_adjustment); + budgetAdjustmentStatus.at(prefix).set("N/A"); + totalVotes.at(prefix).set(BigInteger.ZERO); + totalVoters.at(prefix).set(0); + approvedVotes.at(prefix).set(BigInteger.ZERO); + rejectedVotes.at(prefix).set(BigInteger.ZERO); + budgetApprovedVotes.at(prefix).set(BigInteger.ZERO); + budgetRejectedVotes.at(prefix).set(BigInteger.ZERO); + ipfsLink.at(prefix).set(progressData.ipfs_link); + } + + public static Map getDataFromProgressReportDB(String prefix) { + Map entryMap = + Map.ofEntries(Map.entry(IPFS_HASH, ipfsHash.at(prefix).getOrDefault("")), + Map.entry(REPORT_HASH, reportHash.at(prefix).getOrDefault("")), + Map.entry(PROGRESS_REPORT_TITLE, progressReportTitle.at(prefix).getOrDefault("")), + Map.entry(TIMESTAMP, timestamp.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(ADDITIONAL_BUDGET, additionalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(ADDITIONAL_DURATION, additionalMonth.at(prefix).getOrDefault(0)), + Map.entry(STATUS, status.at(prefix).getOrDefault("")), + Map.entry(TX_HASH, txHash.at(prefix).getOrDefault("")), + Map.entry(TOTAL_VOTES, totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(APPROVED_VOTES, approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(REJECTED_VOTES, rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(TOTAL_VOTERS, totalVoters.at(prefix).getOrDefault(0)), + Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), + Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size()), + Map.entry(BUDGET_APPROVED_VOTES, budgetApprovedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(BUDGET_REJECTED_VOTES, budgetRejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(BUDGET_APPROVE_VOTERS, budgetApproveVoters.at(prefix).size()), + Map.entry(BUDGET_REJECT_VOTERS, budgetRejectVoters.at(prefix).size()), + Map.entry(BUDGET_ADJUSTMENT_STATUS, budgetAdjustmentStatus.at(prefix).getOrDefault("")), + Map.entry(IPFS_LINK, ipfsLink.at(prefix).getOrDefault("")), + Map.entry(PERCENTAGE_COMPLETED, percentageCompleted.at(prefix).getOrDefault(0)), + Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false))); + return entryMap; + } + +} diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java new file mode 100644 index 00000000..016387d9 --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java @@ -0,0 +1,107 @@ +package community.icon.cps.score.cpscore.db; + +import score.*; + +import java.math.BigInteger; +import scorex.util.HashMap; +import java.util.Map; +import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; + +import static community.icon.cps.score.cpscore.utils.Constants.*; +import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; + +public class ProposalDataDb { + private static final BranchDB> ipfsHash = Context.newBranchDB(IPFS_HASH, String.class); + private static final BranchDB> projectTitle = Context.newBranchDB(PROJECT_TITLE, String.class); + public static final BranchDB> timestamp = Context.newBranchDB(TIMESTAMP, BigInteger.class); + public static final BranchDB> totalBudget = Context.newBranchDB(TOTAL_BUDGET, BigInteger.class); + public static final BranchDB> projectDuration = Context.newBranchDB(PROJECT_DURATION, Integer.class); + public static final BranchDB> approvedReports = Context.newBranchDB(APPROVED_REPORTS, Integer.class); + public static final BranchDB> sponsorAddress = Context.newBranchDB(SPONSOR_ADDRESS, Address.class); + public static final BranchDB> contributorAddress = Context.newBranchDB(CONTRIBUTOR_ADDRESS, Address.class); + public static final BranchDB> token = Context.newBranchDB(TOKEN, String.class); + public static final BranchDB> ipfsLink = Context.newBranchDB(IPFS_LINK, String.class); + public static final BranchDB> status = Context.newBranchDB(STATUS, String.class); + private static final BranchDB> txHash = Context.newBranchDB(TX_HASH, String.class); + private static final BranchDB> percentageCompleted = Context.newBranchDB(PERCENTAGE_COMPLETED, Integer.class); + public static final BranchDB> votersReasons = Context.newBranchDB(VOTERS_REASON, String.class); + public static final BranchDB> totalVotes = Context.newBranchDB(TOTAL_VOTES, BigInteger.class); + public static final BranchDB> totalVoters = Context.newBranchDB(TOTAL_VOTERS, Integer.class); + public static final BranchDB> approvedVotes = Context.newBranchDB(APPROVED_VOTES, BigInteger.class); + public static final BranchDB> rejectedVotes = Context.newBranchDB(REJECTED_VOTES, BigInteger.class); + public static final BranchDB> abstainedVotes = Context.newBranchDB(ABSTAINED_VOTES, BigInteger.class); + public static final BranchDB> sponsorDepositAmount = Context.newBranchDB(SPONSOR_DEPOSIT, BigInteger.class); + public static final BranchDB> sponsoredTimestamp = Context.newBranchDB(SPONSORED_TIMESTAMP, BigInteger.class); + public static final BranchDB> sponsorDepositStatus = Context.newBranchDB(SPONSOR_DEPOSIT_STATUS, String.class); + public static final BranchDB> sponsorVoteReason = Context.newBranchDB(SPONSOR_VOTE_REASON, String.class); + public static final BranchDB> votersList = Context.newBranchDB(VOTERS_LIST, Address.class); + public static final BranchDB> approveVoters = Context.newBranchDB(APPROVE_VOTERS, Address.class); + public static final BranchDB> rejectVoters = Context.newBranchDB(REJECT_VOTERS, Address.class); + public static final BranchDB> abstainVoters = Context.newBranchDB(ABSTAIN_VOTERS, Address.class); + public static final BranchDB>> votersListIndex = Context.newBranchDB(VOTERS_LIST_INDEXES, Integer.class); + public static final BranchDB> progressReports = Context.newBranchDB(PROGRESS_REPORTS, String.class); + public static final BranchDB> budgetAdjustment = Context.newBranchDB(BUDGET_ADJUSTMENT, Boolean.class); + public static final BranchDB> submitProgressReport = Context.newBranchDB(SUBMIT_PROGRESS_REPORT, Boolean.class); + + public static void addDataToProposalDB(ProposalAttributes proposalData, String prefix) { + ipfsHash.at(prefix).set(proposalData.ipfs_hash); + projectTitle.at(prefix).set(proposalData.project_title); + timestamp.at(prefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); + totalBudget.at(prefix).set(proposalData.total_budget.multiply(EXA)); + projectDuration.at(prefix).set(proposalData.project_duration); + sponsorAddress.at(prefix).set(proposalData.sponsor_address); + ipfsLink.at(prefix).set(proposalData.ipfs_link); + contributorAddress.at(prefix).set(Context.getCaller()); + status.at(prefix).set(SPONSOR_PENDING); + txHash.at(prefix).set(recordTxHash(Context.getTransactionHash())); + percentageCompleted.at(prefix).set(0); + totalVotes.at(prefix).set(BigInteger.ZERO); + totalVoters.at(prefix).set(0); + approvedVotes.at(prefix).set(BigInteger.ZERO); + rejectedVotes.at(prefix).set(BigInteger.ZERO); + approvedReports.at(prefix).set(0); + budgetAdjustment.at(prefix).set(false); + submitProgressReport.at(prefix).set(false); + token.at(prefix).set(proposalData.token); + } + + public static Map getDataFromProposalDB(String prefix) { + String reason = sponsorVoteReason.at(prefix).getOrDefault(""); + if (reason.equalsIgnoreCase("none")) { + reason = ""; + } else { + reason = reason.toString(); + } + + Map entryMap = Map.ofEntries( + Map.entry(IPFS_HASH, ipfsHash.at(prefix).getOrDefault("")), + Map.entry(PROJECT_TITLE, projectTitle.at(prefix).getOrDefault("")), + Map.entry(TIMESTAMP, timestamp.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(TOTAL_BUDGET, totalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(PROJECT_DURATION, projectDuration.at(prefix).getOrDefault(0)), + Map.entry(APPROVED_REPORTS, approvedReports.at(prefix).getOrDefault(0)), + Map.entry(SPONSOR_ADDRESS, sponsorAddress.at(prefix).get()), + Map.entry(CONTRIBUTOR_ADDRESS, contributorAddress.at(prefix).get()), + Map.entry(STATUS, status.at(prefix).getOrDefault("")), + Map.entry(TX_HASH, txHash.at(prefix).getOrDefault("")), + Map.entry(PERCENTAGE_COMPLETED, percentageCompleted.at(prefix).getOrDefault(0)), + Map.entry(TOKEN, token.at(prefix).getOrDefault("")), + Map.entry(TOTAL_VOTES, totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(TOTAL_VOTERS, totalVoters.at(prefix).getOrDefault(0)), + Map.entry(APPROVED_VOTES, approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(REJECTED_VOTES, rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(ABSTAINED_VOTES, abstainedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(SPONSOR_DEPOSIT_AMOUNT, sponsorDepositAmount.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(SPONSORED_TIMESTAMP, sponsoredTimestamp.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(SPONSOR_DEPOSIT_STATUS, sponsorDepositStatus.at(prefix).getOrDefault("")), + Map.entry(SPONSOR_VOTE_REASON, reason), + Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), + Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size()), + Map.entry(ABSTAIN_VOTERS, abstainVoters.at(prefix).size()), + Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false)), + Map.entry(SUBMIT_PROGRESS_REPORT, submitProgressReport.at(prefix).getOrDefault(false))); + return entryMap; + } + + +} diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/ArrayDBUtils.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/ArrayDBUtils.java new file mode 100644 index 00000000..af556c7c --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/ArrayDBUtils.java @@ -0,0 +1,156 @@ +package community.icon.cps.score.cpscore.utils; + +import score.ArrayDB; +import scorex.util.ArrayList; + +import java.util.List; +import java.util.Map; + +public final class ArrayDBUtils { + public static void clearArrayDb(ArrayDB array_db) { + int size = array_db.size(); + for (int i = 0; i < size; i++) { + array_db.pop(); + } + + } + + public static void removeArrayItem(ArrayDB array_db, Object target) { + int size = array_db.size(); + T _out = array_db.get(size - 1); + if (_out.equals(target)) { + array_db.pop(); + return; + } + for (int i = 0; i < size - 1; i++) { + if (array_db.get(i).equals(target)) { + array_db.set(i, _out); + array_db.pop(); + return; + } + } + } + + + public static boolean containsInArrayDb(T value, ArrayDB array) { + boolean contains = false; + if (array == null || value == null) { + return contains; + } + + for (int i = 0; i < array.size(); i++) { + if (array.get(i) != null && array.get(i).equals(value)) { + contains = true; + break; + } + } + return contains; + } + + public static boolean containsInList(T value, List array){ + boolean contains = false; + if (array == null || value == null) { + return contains; + } + + for (int i = 0; i < array.size(); i++) { + if (array.get(i) != null && array.get(i).equals(value)) { + contains = true; + break; + } + } + return contains; + } + + public static String recordTxHash(byte[] tx_hash) { + String tx_hash_string = encodeHexString(tx_hash); + return "0x" + tx_hash_string; + } + + public static String encodeHexString(byte[] byteArray) { + StringBuffer hexStringBuffer = new StringBuffer(); + for (byte b : byteArray) { + hexStringBuffer.append(byteToHex(b)); + } + return hexStringBuffer.toString(); + } + + public static String byteToHex(byte num) { + char[] hexDigits = new char[2]; + hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16); + hexDigits[1] = Character.forDigit((num & 0xF), 16); + return new String(hexDigits); + } + + public static List arrayDBtoList(ArrayDB arraydb) { + List list = new ArrayList<>(); + for (int i = 0; i < arraydb.size(); i++) { + list.add(arraydb.get(i)); + } + return list; + } + + public static List arrayToList(T[] array){ + List list = new ArrayList<>(); + for (int i = 0; i < array.length; i++){ + list.add(array[i]); + } + return list; + } + + public static void mergeSort(String[] array, int left, int right, Map priorityVoteResult) { + if (left < right) { + + int mid = (left + right) / 2; + + mergeSort(array, left, mid, priorityVoteResult); + mergeSort(array, mid + 1, right, priorityVoteResult); + + merge(array, left, mid, right, priorityVoteResult); + } + } + + private static void merge(String[] array, int p, int q, int r, Map priorityVoteResult) { + + int n1 = q - p + 1; + int n2 = r - q; + + String[] L = new String[n1]; + String[] M = new String[n2]; + + for (int i = 0; i < n1; i++) + L[i] = array[p + i]; + for (int j = 0; j < n2; j++) + M[j] = array[q + 1 + j]; + + int i, j, k; + i = 0; + j = 0; + k = p; + + while (i < n1 && j < n2) { + if ((priorityVoteResult.get(L[i])) > (priorityVoteResult.get(M[j]))) { + array[k] = L[i]; + i++; + } else { + array[k] = M[j]; + j++; + } + k++; + } + + while (i < n1) { + array[k] = L[i]; + i++; + k++; + } + + while (j < n2) { + array[k] = M[j]; + j++; + k++; + } + } +} + + diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Checkers.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Checkers.java new file mode 100644 index 00000000..5a68a383 --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Checkers.java @@ -0,0 +1,34 @@ +package community.icon.cps.score.cpscore.utils; + +import score.Address; +import score.Context; + +import static community.icon.cps.score.cpscore.utils.Constants.TAG; +import community.icon.cps.score.cpscore.SetterGetter; +import community.icon.cps.score.cpscore.CPSCore; + +public class Checkers { + public static void onlyOwner() { + Address caller = Context.getCaller(); + Address owner = Context.getOwner(); + Context.require(caller.equals(owner), "SenderNotScoreOwner: Sender=" + caller + " Owner=" + owner); + } + + public static void validateAdmins() { + CPSCore cpsCore = new CPSCore(); + Context.require(cpsCore.isAdmin(Context.getCaller()), + TAG + ": Only Admins can call this method"); + + } + + public static void validateAdminScore(Address scoreAddress) { + validateAdmins(); + Context.require(scoreAddress.isContract(), scoreAddress + " is not a SCORE Address"); + + } + + public static void checkMaintenance() { + SetterGetter setterGetter = new SetterGetter(); + Context.require(!setterGetter.maintenance.get(), "Maintenance mode is on. Will resume soon."); + } +} diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java new file mode 100644 index 00000000..1445c85f --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java @@ -0,0 +1,189 @@ +package community.icon.cps.score.cpscore.utils; + +import score.Address; + +import java.math.BigInteger; +import java.util.List; + +public class Constants { + public static final String TAG = "CPS Score"; + + + public static final BigInteger EXA = new BigInteger("1000000000000000000"); + public static final Integer MINIMUM_PREPS = 7; + + public static final Integer MAX_PROJECT_PERIOD = 12; + public static final double MAJORITY = 0.67; + public static final BigInteger DAY_COUNT = BigInteger.valueOf(15); + public static final BigInteger BLOCKS_DAY_COUNT = BigInteger.valueOf(43120); + + public static final String PROPOSAL_DB_PREFIX = "proposal"; + public static final String PROGRESS_REPORT_DB_PREFIX = "progressReport"; + + public static final String APPLICATION_PERIOD = "Application Period"; + public static final String VOTING_PERIOD = "Voting Period"; + public static final String TRANSITION_PERIOD = "Transition Period"; + + // Bond Status + public static final String BOND_RECEIVED = "bond_received"; + public static final String BOND_APPROVED = "bond_approved"; + public static final String BOND_RETURNED = "bond_returned"; + public static final String BOND_CANCELLED = "bond_cancelled"; + + // SCOREs Constants + public static final String CPS_TREASURY_SCORE = "_cps_treasury_score"; + public static final String CPF_SCORE = "_cpf_score"; + public static final String BALANCED_DOLLAR = "balanced_dollar"; + + // PERIOD CONSTANTS + public static final String INITIAL_BLOCK = "initial_block"; + public static final String PERIOD_DETAILS = "_period_details"; + public static final String PERIOD_NAME = "period_name"; + public static final String PREVIOUS_PERIOD_NAME = "previous_period_name"; + public static final String PERIOD_SPAN = "period_span"; + public static final String LASTBLOCK = "last_block"; + public static final String CURRENTBLOCK = "current_block"; + public static final String NEXTBLOCK = "next_block"; + public static final String REMAINING_TIME = "remaining_time"; + public static final String UPDATE_PERIOD_INDEX = "update_period_index"; + + // PREPS Related Constants + public static final String MAIN_PREPS = "main_preps"; + public static final String ALL_PREPS = "_all_preps"; + public static final String ADMINS = "admins"; + public static final String UNREGISTERED_PREPS = "unregistered_preps"; + public static final String REGISTERED_PREPS = "registered_preps"; + public static final String INACTIVE_PREPS = "inactive_preps"; + public static final String PREP_NAME = "prep_name"; + + public static final String ICX = "ICX"; + public static final String bnUSD = "bnUSD"; + public static final List SUPPORTED_TOKENS = List.of(ICX, bnUSD); + + public static final String MAINTENANCE = "maintenance"; + public static final String MESSAGE = "message"; + + //VarDB/ArrayDB Params + public static final String PROPOSALS_KEY_LIST = "proposals_key_list"; + public static final String PROPOSALS_KEY_LIST_INDEX = "proposals_key_list_index"; + public static final String PROGRESS_KEY_LIST = "progress_key_list"; + public static final String PROGRESS_KEY_LIST_INDEX = "progress_key_list_index"; + public static final String CONTRIBUTORS = "contributors"; + public static final String SPONSORS = "sponsors"; + public static final String BUDGET_APPROVALS_LIST = "budget_approvals_list"; + public static final String SPONSOR_ADDRESS = "sponsor_address"; + public static final String TOTAL_BUDGET = "total_budget"; + public static final String ACTIVE_PROPOSALS = "active_proposals"; + public static final String VOTING_PROPOSALS = "voting_proposals"; + public static final String VOTING_PROGRESS_REPORTS = "voting_progress_reports"; + public static final String AMOUNT = "_total_amount"; + public static final String ADDRESS = "address"; + + // Proposals and Progress reports keys + public static final String PROPOSAL = "proposal"; + public static final String PROGRESS_REPORTS = "progress_reports"; + public static final String NEW_PROGRESS_REPORT = "new_progress_report"; + public static final String PROJECT_TITLE = "project_title"; + public static final String PROGRESS_REPORT_TITLE = "progress_report_title"; + public static final String TOTAL_VOTES = "total_votes"; + public static final String TOTAL_VOTERS = "total_voters"; + public static final String REJECTED_VOTES = "rejected_votes"; + public static final String APPROVED_VOTES = "approved_votes"; + public static final String ABSTAINED_VOTES = "abstained_votes"; + public static final String REJECT_VOTERS = "reject_voters"; + public static final String APPROVE_VOTERS = "approve_voters"; + public static final String ABSTAIN_VOTERS = "abstain_voters"; + public static final String VOTERS_REASON = "voters_reasons"; + public static final String SUBMIT_PROGRESS_REPORT = "submit_progress_report"; + public static final String SPONSORED_TIMESTAMP = "sponsored_timestamp"; + public static final String SPONSOR_DEPOSIT_STATUS = "sponsor_deposit_status"; + public static final String SPONSOR_VOTE_REASON = "sponsor_vote_reason"; + public static final String VOTERS_LIST = "voters_list"; + public static final String VOTERS_LIST_INDEXES = "voters_list_indexes"; + public static final String BUDGET_VOTERS_LIST_INDICES = "budget_voters_list_indexes"; + + + public static final String TIMESTAMP = "timestamp"; + public static final String TOKEN = "token"; + public static final String CONTRIBUTOR_ADDRESS = "contributor_address"; + public static final String TX_HASH = "tx_hash"; + public static final String IPFS_HASH = "ipfs_hash"; + public static final String REPORT_KEY = "report_key"; + public static final String REPORT_HASH = "report_hash"; + public static final String PROJECT_DURATION = "project_duration"; + public static final String APPROVED_REPORTS = "approved_reports"; + public static final String IPFS_LINK = "ipfs_link"; + public static final String PERCENTAGE_COMPLETED = "percentage_completed"; + public static final String ADDITIONAL_BUDGET = "additional_budget"; + public static final String ADDITIONAL_DURATION = "additional_month"; + public static final String BUDGET_ADJUSTMENT = "budget_adjustment"; + public static final String BUDGETADJUSTMENT = "budgetAdjustment"; + public static final String BUDGET_ADJUSTMENT_STATUS = "budget_adjustment_status"; + public static final String BUDGET_APPROVED_VOTES = "budget_approved_votes"; + public static final String BUDGET_REJECTED_VOTES = "budget_rejected_votes"; + public static final String BUDGET_APPROVE_VOTERS = "budget_approve_voters"; + public static final String BUDGET_REJECT_VOTERS = "budget_reject_voters"; + public static final String SPONSOR_DEPOSIT_AMOUNT = "sponsor_deposit_amount"; + public static final String SPONSOR_DEPOSIT = "sponsor_deposit"; + public static final String PREPS_DENYLIST_STATUS = "preps_denylist_status"; + public static final String DENYLIST = "denylist"; + public static final String PENALTY_AMOUNT = "penalty_amount"; + public static final String STATUS = "status"; + public static final String DATA = "data"; + public static final String COUNT = "count"; + + public static final String DELEGATION_SNAPSHOT = "delegation_snapshot"; + public static final String MAX_DELEGATION = "max_delegation"; + public static final String PROPOSAL_FUND = "proposal_fund"; + public static final String PROPOSAL_FEES = "proposal_fees"; + public static final String SWAP_BLOCK_HEIGHT = "swap_block_height"; + public static final String SWAP_COUNT = "swap_count"; + public static final String PERIOD_COUNT = "period_count"; + + public static final String PROPOSAL_RANK = "proposal_rank"; + public static final String PRIORITY_VOTED_PREPS = "priority_voted_preps"; + + + // VOTE KEYS + public static final String VOTE = "vote"; + public static final String INDEX = "index"; + public static final String CHANGE_VOTE = "change_vote"; + public static final String VOTE_REASON = "vote_reason"; + public static final String APPROVE = "_approve"; + public static final String REJECT = "_reject"; + public static final String ABSTAIN = "_abstain"; + public static final String ACCEPT = "_accept"; + + public static final Integer APPROVE_ = 1; + public static final Integer REJECT_ = 2; + public static final Integer ABSTAIN_ = 3; + + public static final Integer VOTED = 1; + public static final Integer NOT_VOTED = 0; + + // Sponsor Fee + public static final Integer APPLICATION_FEE = 50; + public static final BigInteger SWAP_BLOCK_DIFF = BigInteger.valueOf(5); + + + public static final String SPONSOR_PENDING = "_sponsor_pending"; + public static final String PENDING = "_pending"; + public static final String ACTIVE = "_active"; + public static final String PAUSED = "_paused"; + public static final String DISQUALIFIED = "_disqualified"; + public static final String REJECTED = "_rejected"; + public static final String COMPLETED = "_completed"; + public static final List STATUS_TYPE = List.of(SPONSOR_PENDING, PENDING, ACTIVE, PAUSED, DISQUALIFIED, REJECTED, COMPLETED); + + public static final String WAITING = "_waiting"; + public static final String APPROVED = "_approved"; + public static final String PROGRESS_REPORT_REJECTED = "_progress_report_rejected"; + public static final List PROGRESS_REPORT_STATUS_TYPE = List.of(APPROVED, WAITING, PROGRESS_REPORT_REJECTED); + + public static final String SPONSOR_BOND_RETURN = "sponsor_bond_return"; + + public static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000"); + + public static final Integer PENALTY_LEVELS = 3; + +} From 12cc0120c0958f6f91f2b06612300bd5bee93bc4 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 8 Nov 2022 22:10:37 +0545 Subject: [PATCH 063/112] update contract interfaces --- .../lib/interfaces/CPFTreasuryInterface.java | 118 +++++++ .../lib/interfaces/CPSCoreInterface.java | 311 ++++++++++++++++++ .../lib/interfaces/CPSTreasuryInterface.java | 91 +++++ .../score/lib/interfaces/DexInterface.java | 28 ++ .../score/lib/interfaces/RouterInterface.java | 18 + .../score/lib/interfaces/SystemInterface.java | 45 +++ .../score/lib/interfaces/bnUSDInterface.java | 10 + .../score/lib/interfaces/sICXInterface.java | 10 + .../cps/score/lib/interfaces/tokens/IRC2.java | 52 +++ .../icon/cps/score/lib/tokens/IRC2Base.java | 130 ++++++++ 10 files changed, 813 insertions(+) create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPFTreasuryInterface.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSTreasuryInterface.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/DexInterface.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/RouterInterface.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/SystemInterface.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/bnUSDInterface.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/sICXInterface.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/interfaces/tokens/IRC2.java create mode 100644 score-lib/src/main/java/community/icon/cps/score/lib/tokens/IRC2Base.java diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPFTreasuryInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPFTreasuryInterface.java new file mode 100644 index 00000000..347aaf15 --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPFTreasuryInterface.java @@ -0,0 +1,118 @@ +package community.icon.cps.score.lib.interfaces; + +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; + +import score.Address; +import score.Context; +import score.VarDB; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Optional; +import score.annotation.Payable; + +import java.math.BigInteger; +import java.util.List; +import java.util.Map; + +@ScoreClient +@ScoreInterface +public interface CPFTreasuryInterface { + @External(readonly = true) + String name(); + + @External + void setCpsScore(Address _score); + + @External(readonly = true) + Address getCpsScore(); + + @External + void setCpsTreasuryScore(Address _score); + + @External(readonly = true) + Address getCpsTreasuryScore(); + + @External + void setBnUSDScore(Address _score); + + @External(readonly = true) + Address getBnUSDScore(); + + @External + void setSicxScore(Address _score); + + @External(readonly = true) + Address getSicxScore(); + + @External + void setDexScore(Address _score); + + @External(readonly = true) + Address getDexScore(); + + @External + void setRouterScore(Address _score); + + @External(readonly = true) + Address getRouterScore(); + + @External + void setMaximumTreasuryFundIcx(BigInteger _value); + + @External + void setMaximumTreasuryFundBnusd(BigInteger _value); + + @External(readonly = true) + Map get_total_funds(); + + @External(readonly = true) + Map get_remaining_swap_amount(); + + @External + void transfer_proposal_fund_to_cps_treasury(String ipfs_key, int total_installment_count, + Address sponsor_address, Address contributor_address, + String token_flag, BigInteger _total_budget); + + @External + void update_proposal_fund(String ipfs_key, @Optional String flag, @Optional BigInteger _added_budget, + @Optional int _total_installment_count); + + @External + @Payable + void add_fund(); + + @External + void swapIcxBnusd(BigInteger amount); + + @External + void swap_tokens(int _count); + + @External(readonly = true) + Map get_swap_state_status(); + + @External + void reset_swap_state(); + + @External(readonly = true) + Map get_proposal_details(@Optional int start_index, @Optional int end_index); + + @External + void tokenFallback(Address from, BigInteger value, byte[] _data); + + @Payable + void fallback(); + + //EventLogs + @EventLog(indexed = 1) + void FundReturned(Address _sponsor_address, String note); + + @EventLog(indexed = 1) + void ProposalFundTransferred(String _ipfs_key, String note); + + @EventLog(indexed = 1) + void ProposalDisqualified(String _ipfs_key, String note); + + @EventLog(indexed = 1) + void FundReceived(Address _sponsor_address, String note); +} diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java new file mode 100644 index 00000000..43f9415b --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java @@ -0,0 +1,311 @@ +package community.icon.cps.score.lib.interfaces; + +import score.Address; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Optional; +import score.annotation.Payable; + +import java.math.BigInteger; +import java.util.List; +import java.util.Map; + +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; + +@ScoreClient +@ScoreInterface +public interface CPSCoreInterface { + + public static class ProposalAttributes { + public String ipfs_hash; + public String project_title; + public int project_duration; + public BigInteger total_budget; + public String token; + public Address sponsor_address; + public String ipfs_link; + } + + public static class ProgressReportAttributes { + public String ipfs_hash; + public String report_hash; + public String ipfs_link; + public String progress_report_title; + public Boolean budget_adjustment; + public BigInteger additional_budget; + public int additional_month; + public int percentage_completed; + } + @External(readonly = true) + String name(); + + String proposalPrefix(String proposalKey); + + String progressReportPrefix(String progressKey); + + + @External + void set_cps_treasury_score(Address _score); + + @External + void setCpsTreasuryScore(Address score); + + + @External(readonly = true) + Address get_cps_treasury_score(); + + @External(readonly = true) + Address getCpsTreasuryScore(); + + + @External + void set_cpf_treasury_score(Address _score); + + @External + void setCpfTreasuryScore(Address score); + + + @External(readonly = true) + Address get_cpf_treasury_score(); + + @External(readonly = true) + Address getCpfTreasuryScore(); + + + @External + void set_bnUSD_score(Address _score); + + + @External(readonly = true) + Address get_bnUSD_score(); + + + @External(readonly = true) + boolean is_admin(Address _address); + + @External + void toggleBudgetAdjustmentFeature(); + + @External(readonly = true) + boolean getBudgetAdjustmentFeature(); + + + @External + void toggle_maintenance(); + + @External(readonly = true) + boolean getMaintenanceMode(); + + @Payable + void fallback(); + + + @External + void add_admin(Address _address); + + + @External + void remove_admin(Address _address); + + + @External + void unregister_prep(); + + + @External + void register_prep(); + + @External(readonly = true) + boolean checkPriorityVoting(Address prep); + + @External(readonly = true) + List sortPriorityProposals(); + + @External(readonly = true) + Map getPriorityVoteResult(); + + @External + void votePriority(String[] proposals); + + + @External + void set_prep_penalty_amount(BigInteger[] _penalty); + + + @External + void set_initialBlock(); + + + @External(readonly = true) + Map login_prep(Address _address); + + + @External(readonly = true) + List
get_admins(); + + @SuppressWarnings("unchecked") + + @External(readonly = true) + Map get_remaining_fund(); + + + @External(readonly = true) + List> get_PReps(); + + + @External(readonly = true) + List
get_denylist(); + + + @External(readonly = true) + Map get_period_status(); + + + @External(readonly = true) + List
get_contributors(); + + + @External(readonly = true) + Map check_claimable_sponsor_bond(Address _address); + + + @Payable + @External + void submit_proposal(ProposalAttributes _proposals); + + + @External + void vote_proposal(String _ipfs_key, String _vote, String _vote_reason, @Optional boolean _vote_change); + + + @External + void submit_progress_report(ProgressReportAttributes _progress_report); + + + @External + void vote_progress_report(String _ipfs_key, String _report_key, String _vote, String _vote_reason, @Optional String _budget_adjustment_vote, @Optional boolean _vote_change); + + + @External(readonly = true) + List get_proposals_keys_by_status(String _status); + + + @External(readonly = true) + int check_change_vote(Address _address, String _ipfs_hash, String _proposal_type); + + + @External(readonly = true) + Map get_project_amounts(); + + + @External(readonly = true) + Map get_sponsors_record(); + + @External + void update_period(); + + + @External(readonly = true) + Map get_proposal_details(String _status, @Optional Address _wallet_address, @Optional int _start_index, @Optional int _end_index); + + @External(readonly = true) + Map get_proposal_details_by_hash(String _ipfs_key); + + + @External(readonly = true) + Map get_progress_reports(String _status, @Optional int _start_index, @Optional int _end_index); + + + @External(readonly = true) + Map get_progress_reports_by_hash(String _report_key); + + + @External(readonly = true) + Map get_progress_reports_by_proposal(String _ipfs_key); + + + @External(readonly = true) + Map get_sponsors_requests(String _status, Address _sponsor_address, @Optional int _start_index, @Optional int _end_index); + + @External(readonly = true) + + Map get_vote_result(String _ipfs_key); + + @External(readonly = true) + + Map get_progress_report_result(String _report_key); + + @External(readonly = true) + + Map get_budget_adjustment_vote_result(String _report_key); + + @External + + void tokenFallback(Address _from, BigInteger _value, byte[] _data); + + @External + + void remove_denylist_preps(); + + @External + + void claim_sponsor_bond(); + + @External + + void set_swap_count(int value); + + @External + + void update_next_block(int blockCount); + + + @External(readonly = true) + List> get_active_proposals(); + + @External(readonly = true) + Map get_proposal_detail_by_wallet(Address _wallet_address); + + List> getProposalsHistory(); + + // EventLogs + @EventLog(indexed = 1) + void ProposalSubmitted(Address _sender_address, String note); + + @EventLog(indexed = 1) + void ProgressReportSubmitted(Address _sender_address, String _project_title); + + @EventLog(indexed = 1) + void SponsorBondReceived(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void SponsorBondRejected(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void VotedSuccessfully(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void PRepPenalty(Address _prep_address, String _notes); + + @EventLog(indexed = 1) + void UnRegisterPRep(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void RegisterPRep(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void SponsorBondReturned(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void PeriodUpdate(String _notes); + + @EventLog(indexed = 1) + void SponsorBondClaimed(Address _receiver_address, BigInteger _fund, String note); + + @EventLog(indexed = 1) + void PriorityVote(Address _address, String note); + + @External(readonly = true) + int getPeriodCount(); +} \ No newline at end of file diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSTreasuryInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSTreasuryInterface.java new file mode 100644 index 00000000..0959dc03 --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSTreasuryInterface.java @@ -0,0 +1,91 @@ +package community.icon.cps.score.lib.interfaces; + +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; + +import score.Address; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Optional; +import score.annotation.Payable; + +import java.math.BigInteger; +import java.util.List; +import java.util.Map; + +@ScoreClient +@ScoreInterface +public interface CPSTreasuryInterface { + @External(readonly = true) + String name(); + + @Payable + void fallback(); + + @External + void setCpsScore(Address _score); + + @External(readonly = true) + //Todo java convention in get methods?? + Address getCpsScore(); + + @External + void setCpfTreasuryScore(Address _score); + + @External(readonly = true) + Address getCpfTreasuryScore(); + + @External + void setBnUSDScore(Address _score); + + @External(readonly = true) + Address getBnUSDScore(); + + @External(readonly = true) + Map get_contributor_projected_fund(Address _wallet_address); + + @External(readonly = true) + List getContributorProjects(Address address); + + @External(readonly = true) + List getSponsorProjects(Address address); + + @External(readonly = true) + Map get_sponsor_projected_fund(Address _wallet_address); + + @External + @Payable + void update_proposal_fund(String ipfs_key, BigInteger added_budget, BigInteger _added_sponsor_reward, + int _added_installment_count); + + @External + void send_installment_to_contributor(String _ipfs_key); + + @External + void send_reward_to_sponsor(String _ipfs_key); + + @External + void disqualify_project(String _ipfs_key); + + @External + void claim_reward(); + + @External + void tokenFallback(Address from, BigInteger value, byte[] _data); + + // for migration into java contract + @External + void updateSponsorAndContributorProjects(); + + @EventLog(indexed = 1) + void ProposalDisqualified(String _ipfs_key, String note); + + @EventLog(indexed = 1) + void ProposalFundDeposited(String _ipfs_key, String note); + + @EventLog(indexed = 1) + void ProposalFundSent(Address _receiver_address, String note); + + @EventLog(indexed = 1) + void ProposalFundWithdrawn(Address _receiver_address, String note); +} diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/DexInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/DexInterface.java new file mode 100644 index 00000000..1be7d1a4 --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/DexInterface.java @@ -0,0 +1,28 @@ +package community.icon.cps.score.lib.interfaces; + +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; +import score.Address; +import score.annotation.EventLog; +import score.annotation.External; + +import java.math.BigInteger; + +@ScoreInterface +@ScoreClient +public interface DexInterface { + + @External + void setSicxScore(Address _score); + @EventLog + void Deposit(Address from_token, Address from, BigInteger value); + + @EventLog(indexed = 2) + void Swap(BigInteger _id, Address _baseToken, Address _fromToken, Address _toToken, + Address _sender, Address _receiver, BigInteger _fromValue, BigInteger _toValue, + BigInteger _timestamp, BigInteger _lpFees, BigInteger _balnFees, BigInteger _poolBase, + BigInteger _poolQuote, BigInteger _endingPrice, BigInteger _effectiveFillPrice); + + @External + void tokenFallback(Address _from, BigInteger _value, byte[] _data); +} diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/RouterInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/RouterInterface.java new file mode 100644 index 00000000..efb9b81b --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/RouterInterface.java @@ -0,0 +1,18 @@ +package community.icon.cps.score.lib.interfaces; + +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; +import score.Address; +import score.annotation.External; +import score.annotation.Optional; +import score.annotation.Payable; + +import java.math.BigInteger; + +@ScoreInterface +@ScoreClient +public interface RouterInterface { + @Payable + @External + void route(Address[] _path, @Optional BigInteger _minReceive); +} diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/SystemInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/SystemInterface.java new file mode 100644 index 00000000..76d46074 --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/SystemInterface.java @@ -0,0 +1,45 @@ +package community.icon.cps.score.lib.interfaces; + +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; +import score.Address; +import score.annotation.Payable; + +import javax.management.MBeanServerInvocationHandler; +import java.math.BigInteger; +import java.util.Map; + +@ScoreClient +@ScoreInterface +public interface SystemInterface { + public static class Delegation{ + public Address address; + public BigInteger value; + } + + public static class Bond{ + public Address address; + public BigInteger value; + } + Map getIISSInfo(); + + Map queryIScore(Address address); + + Map getStake(Address address); + + Map getDelegation(Address address); + + Map getPReps(BigInteger startRanking, BigInteger endRanking); + + void setStake(BigInteger value); + + void setDelegation(Delegation[] delegations); + Map getPRepTerm(); + + void setBond(Bond[] bonds); + + void setBonderList(Address[] bonderList); + + @Payable + void registerPRep(String name, String email, String country, String city, String website, String details, String p2pEndpoint); +} diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/bnUSDInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/bnUSDInterface.java new file mode 100644 index 00000000..21c472a5 --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/bnUSDInterface.java @@ -0,0 +1,10 @@ +package community.icon.cps.score.lib.interfaces; + +import community.icon.cps.score.lib.interfaces.tokens.IRC2; +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; + +@ScoreInterface +@ScoreClient +public interface bnUSDInterface extends IRC2 { +} diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/sICXInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/sICXInterface.java new file mode 100644 index 00000000..9433f219 --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/sICXInterface.java @@ -0,0 +1,10 @@ +package community.icon.cps.score.lib.interfaces; + +import community.icon.cps.score.lib.interfaces.tokens.IRC2; +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; + +@ScoreInterface +@ScoreClient +public interface sICXInterface extends IRC2 { +} diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/tokens/IRC2.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/tokens/IRC2.java new file mode 100644 index 00000000..15a81ce2 --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/tokens/IRC2.java @@ -0,0 +1,52 @@ +package community.icon.cps.score.lib.interfaces.tokens; + +import foundation.icon.score.client.ScoreInterface; +import score.Address; +import score.annotation.Optional; + +import java.math.BigInteger; + +@ScoreInterface +public interface IRC2 { + /** + * Returns the name of the token. (e.g. "MySampleToken") + */ + String name(); + + /** + * Returns the symbol of the token. (e.g. "MST") + */ + String symbol(); + + /** + * Returns the number of decimals the token uses. (e.g. 18) + */ + BigInteger decimals(); + + /** + * Returns the total token supply. + */ + BigInteger totalSupply(); + + /** + * Returns the account balance of another account with address {@code _owner}. + */ + BigInteger balanceOf(Address _owner); + + /** + * Transfers {@code _value} amount of tokens to address {@code _to}, and MUST fire the {@code Transfer} event. + * This function SHOULD throw if the caller account balance does not have enough tokens to spend. + * If {@code _to} is a contract, this function MUST invoke the function {@code tokenFallback(Address, int, bytes)} + * in {@code _to}. If the {@code tokenFallback} function is not implemented in {@code _to} (receiver contract), + * then the transaction must fail and the transfer of tokens should not occur. + * If {@code _to} is an externally owned address, then the transaction must be sent without trying to execute + * {@code tokenFallback} in {@code _to}. {@code _data} can be attached to this token transaction. + * {@code _data} can be empty. + */ + void transfer(Address _to, BigInteger _value, @Optional byte[] _data); + + /** + * (EventLog) Must trigger on any successful token transfers. + */ + void Transfer(Address _from, Address _to, BigInteger _value, byte[] _data); +} diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/tokens/IRC2Base.java b/score-lib/src/main/java/community/icon/cps/score/lib/tokens/IRC2Base.java new file mode 100644 index 00000000..c837942d --- /dev/null +++ b/score-lib/src/main/java/community/icon/cps/score/lib/tokens/IRC2Base.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package community.icon.cps.score.lib.tokens; + +import community.icon.cps.score.lib.interfaces.tokens.IRC2; +import score.Address; +import score.Context; +import score.DictDB; +import score.VarDB; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Optional; + +import java.math.BigInteger; + +public class IRC2Base implements IRC2 { + + private final static String NAME = "name"; + private final static String SYMBOL = "symbol"; + private final static String DECIMALS = "decimals"; + private final static String TOTAL_SUPPLY = "total_supply"; + private final static String BALANCES = "balances"; + + static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); + + private final VarDB name = Context.newVarDB(NAME, String.class); + private final VarDB symbol = Context.newVarDB(SYMBOL, String.class); + private final VarDB decimals = Context.newVarDB(DECIMALS, BigInteger.class); + private final VarDB totalSupply = Context.newVarDB(TOTAL_SUPPLY, BigInteger.class); + protected final DictDB balances = Context.newDictDB(BALANCES, BigInteger.class); + + protected IRC2Base(String _tokenName, String _symbolName, @Optional BigInteger _decimals) { + if (this.name.get() == null) { + _decimals = _decimals == null ? BigInteger.valueOf(18L) : _decimals; + Context.require(_decimals.compareTo(BigInteger.ZERO) >= 0, "Decimals cannot be less than zero"); + + this.name.set(ensureNotEmpty(_tokenName)); + this.symbol.set(ensureNotEmpty(_symbolName)); + this.decimals.set(_decimals); + } + } + + @EventLog(indexed = 3) + public void Transfer(Address _from, Address _to, BigInteger _value, byte[] _data) { + } + + private String ensureNotEmpty(String str) { + Context.require(str != null && !str.trim().isEmpty(), "str is null or empty"); + assert str != null; + return str.trim(); + } + + @External(readonly = true) + public String name() { + return name.get(); + } + + @External(readonly = true) + public String symbol() { + return symbol.get(); + } + + @External(readonly = true) + public BigInteger decimals() { + return decimals.get(); + } + + @External(readonly = true) + public BigInteger totalSupply() { + return totalSupply.getOrDefault(BigInteger.ZERO); + } + + @External(readonly = true) + public BigInteger balanceOf(Address _owner) { + return balances.getOrDefault(_owner, BigInteger.ZERO); + } + + @External + public void transfer(Address _to, BigInteger _value, @Optional byte[] _data) { + transfer(Context.getCaller(), _to, _value, _data); + } + + protected void transfer(Address _from, Address _to, BigInteger _value, byte[] _data) { + Context.require(_value.compareTo(BigInteger.ZERO) >= 0, this.name.get() + ": _value needs to be positive"); + Context.require(balanceOf(_from).compareTo(_value) >= 0, this.name.get() + ": Insufficient balance"); + + this.balances.set(_from, balanceOf(_from).subtract(_value)); + this.balances.set(_to, balanceOf(_to).add(_value)); + + byte[] dataBytes = (_data == null) ? "None".getBytes() : _data; + Transfer(_from, _to, _value, dataBytes); + + if (_to.isContract()) { + Context.call(_to, "tokenFallback", _from, _value, dataBytes); + } + } + + protected void mint(Address owner, BigInteger amount) { + Context.require(!ZERO_ADDRESS.equals(owner), this.name.get() + ": Owner address cannot be zero address"); + Context.require(amount.compareTo(BigInteger.ZERO) >= 0, this.name.get() + ": Amount needs to be positive"); + + totalSupply.set(totalSupply().add(amount)); + balances.set(owner, balanceOf(owner).add(amount)); + Transfer(ZERO_ADDRESS, owner, amount, "mint".getBytes()); + } + + protected void burn(Address owner, BigInteger amount) { + Context.require(!ZERO_ADDRESS.equals(owner), this.name.get() + ": Owner address cannot be zero address"); + Context.require(amount.compareTo(BigInteger.ZERO) >= 0, this.name.get() + ": Amount needs to be positive"); + Context.require(balanceOf(owner).compareTo(amount) >= 0, this.name.get() + ": Insufficient Balance"); + + balances.set(owner, balanceOf(owner).subtract(amount)); + totalSupply.set(totalSupply().subtract(amount)); + Transfer(owner, ZERO_ADDRESS, amount, "burn".getBytes()); + } +} From 3494b3a4017961eedabefc492c788a049e9961aa Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 9 Nov 2022 10:51:17 +0545 Subject: [PATCH 064/112] integration tests added for CPS project --- .../score/cpstreasury/CPSTreasuryIntTest.java | 371 +++++++++++++++++- .../icon/cps/score/test/integration/CPS.java | 116 +++++- .../integration/ScoreIntegrationTest.java | 116 +++++- 3 files changed, 582 insertions(+), 21 deletions(-) diff --git a/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java b/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java index 2e2119a2..efe79e39 100644 --- a/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java +++ b/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java @@ -1,40 +1,393 @@ package community.icon.cps.score.cpstreasury; -import community.icon.cps.score.lib.interfaces.CPFTreasuryInterfaceScoreClient; -import community.icon.cps.score.lib.interfaces.CPSTreasuryInterfaceScoreClient; +import com.eclipsesource.json.JsonObject; +import community.icon.cps.score.lib.interfaces.*; + import community.icon.cps.score.test.integration.CPS; -import community.icon.cps.score.test.integration.ScoreIntegrationTest; +import foundation.icon.icx.KeyWallet; import foundation.icon.icx.Wallet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import foundation.icon.score.client.DefaultScoreClient; import org.junit.jupiter.api.*; +import score.Address; import java.math.BigInteger; +import java.util.Map; + +import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; +import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class CPSTreasuryIntTest { private static CPS cps; - private static Wallet tester; + private final KeyWallet tester = cps.user; + private final KeyWallet tester2 = cps.testUser; + + private final KeyWallet prepWallet1 = cps.prepWallet1; + private final KeyWallet prepWallet2 = cps.prepWallet2; + private final KeyWallet prepWallet3 = cps.prepWallet3; + private final KeyWallet prepWallet4 = cps.prepWallet4; + private final KeyWallet prepWallet5 = cps.prepWallet5; + private final KeyWallet prepWallet6 = cps.prepWallet6; + private final KeyWallet prepWallet7 = cps.prepWallet7; + public static final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L); + private static Wallet owner; private static CPSTreasuryInterfaceScoreClient cpsTreasury; private static CPFTreasuryInterfaceScoreClient cpfTreasury; + private static CPSCoreInterfaceScoreClient cpsMain; + + private static DexInterfaceScoreClient dex; + private static RouterInterfaceScoreClient router; + private static bnUSDInterfaceScoreClient bnusd; + private static sICXInterfaceScoreClient sicx; + + DefaultScoreClient clientWithTester = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , tester, cps.cpsCore._address()); + + DefaultScoreClient clientWithTester2 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , tester2, cps.cpsCore._address()); + + DefaultScoreClient prepClient1 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , prepWallet1, cps.cpsCore._address()); + + DefaultScoreClient bnUSDClient2 = new DefaultScoreClient(cps.bnusd.endpoint(), cps.bnusd._nid() + , prepWallet2, cps.bnusd._address()); + + + DefaultScoreClient prepClient2 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , prepWallet2, cps.cpsCore._address()); + DefaultScoreClient prepClient3 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , prepWallet3, cps.cpsCore._address()); + DefaultScoreClient prepClient4 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , prepWallet4, cps.cpsCore._address()); + DefaultScoreClient prepClient5 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , prepWallet5, cps.cpsCore._address()); + DefaultScoreClient prepClient6 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , prepWallet6, cps.cpsCore._address()); + DefaultScoreClient prepClient7 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() + , prepWallet7, cps.cpsCore._address()); @BeforeAll static void setup() throws Exception { - tester = ScoreIntegrationTest.createWalletWithBalance(BigInteger.TEN.pow(24)); cps = new CPS(); cps.setupCPS(); owner = cps.owner; + cpsMain = new CPSCoreInterfaceScoreClient(cps.cpsCore); cpsTreasury = new CPSTreasuryInterfaceScoreClient(cps.cpsTreasury); cpfTreasury = new CPFTreasuryInterfaceScoreClient(cps.cpfTreasury); + + dex = new DexInterfaceScoreClient(cps.dex); + bnusd = new bnUSDInterfaceScoreClient(cps.bnusd); + sicx = new sICXInterfaceScoreClient(cps.sicx); + router = new RouterInterfaceScoreClient(cps.router); + } + CPSCoreInterfaceScoreClient cpsMainTestClient1 = new CPSCoreInterfaceScoreClient(clientWithTester); + CPSCoreInterfaceScoreClient cpsMainTestClient2 = new CPSCoreInterfaceScoreClient(clientWithTester2); + CPSCoreInterfaceScoreClient prepSender1 = new CPSCoreInterfaceScoreClient(prepClient1); + bnUSDInterfaceScoreClient bnUSDSender2 = new bnUSDInterfaceScoreClient(bnUSDClient2); + CPSCoreInterfaceScoreClient prepSender2 = new CPSCoreInterfaceScoreClient(prepClient2); + CPSCoreInterfaceScoreClient prepSender3 = new CPSCoreInterfaceScoreClient(prepClient3); + CPSCoreInterfaceScoreClient prepSender4 = new CPSCoreInterfaceScoreClient(prepClient4); + CPSCoreInterfaceScoreClient prepSender5 = new CPSCoreInterfaceScoreClient(prepClient5); + CPSCoreInterfaceScoreClient prepSender6 = new CPSCoreInterfaceScoreClient(prepClient6); + CPSCoreInterfaceScoreClient prepSender7 = new CPSCoreInterfaceScoreClient(prepClient7); + @Test + @Order(1) void name(){ - System.out.println(cpsTreasury.name()); - System.out.println(cpfTreasury.name()); - System.out.println(cpsTreasury._address()); - System.out.println(cpfTreasury._address()); + assertEquals(cpsTreasury.name(), "CPS_TREASURY"); + assertEquals(cpfTreasury.name(), "CPF_TREASURY"); + assertEquals(cpsMain.name(), "CPS Score"); + } + + void addAdminMethod(){ + cpsMain.add_admin(Address.fromString(tester.getAddress().toString())); + cpsMain.add_admin(Address.fromString(owner.getAddress().toString())); + } + + private void setInitialBlockMethod(){ + cpsMain.set_initialBlock(); + } + + void setScores(){ + addAdminMethod(); + cpsMain.set_cps_treasury_score(cpsTreasury._address()); + assertEquals(cpsMain.getCpsTreasuryScore(), cpsTreasury._address()); + cpsMain.set_cpf_treasury_score(cpfTreasury._address()); + assertEquals(cpsMain.get_cpf_treasury_score(), cpfTreasury._address()); + cpsMain.set_bnUSD_score(bnusd._address()); + assertEquals(cpsMain.get_bnUSD_score(), bnusd._address()); + + cpsTreasury.setCpsScore(cpsMain._address()); + assertEquals(cpsTreasury.getCpsScore(), cpsMain._address()); + cpsTreasury.setCpfTreasuryScore(cpfTreasury._address()); + assertEquals(cpsTreasury.getCpfTreasuryScore(), cpfTreasury._address()); + cpsTreasury.setBnUSDScore(bnusd._address()); + assertEquals(cpsTreasury.getBnUSDScore(), bnusd._address()); + + cpfTreasury.setCpsScore(cpsMain._address()); + assertEquals(cpfTreasury.getCpsScore(), cpsMain._address()); + cpfTreasury.setCpsTreasuryScore(cpsTreasury._address()); + assertEquals(cpfTreasury.getCpsTreasuryScore(), cpsTreasury._address()); + cpfTreasury.setBnUSDScore(bnusd._address()); + assertEquals(cpfTreasury.getBnUSDScore(), bnusd._address()); + cpfTreasury.setRouterScore(router._address()); + assertEquals(cpfTreasury.getRouterScore(), router._address()); + cpfTreasury.setDexScore(dex._address()); + assertEquals(cpfTreasury.getDexScore(), dex._address()); + cpfTreasury.setSicxScore(sicx._address()); + assertEquals(cpfTreasury.getSicxScore(), sicx._address()); + + dex.setSicxScore(sicx._address()); + } + + void setCPFTreasuryContract(){ + setScores(); + cpfTreasury.setMaximumTreasuryFundBnusd(BigInteger.valueOf(1000).multiply(EXA)); + cpfTreasury.setMaximumTreasuryFundIcx(BigInteger.valueOf(1000).multiply(EXA)); + + cpfTreasury.add_fund(BigInteger.valueOf(1000).multiply(EXA)); + System.out.println(cpfTreasury.get_remaining_swap_amount()); + + setRouterScore(); + setDexScore(); + cpfTreasury.swapIcxBnusd(BigInteger.valueOf(200).multiply(EXA)); + System.out.println(bnusd.balanceOf(cpfTreasury._address())); + } + + void setRouterScore(){ +// setScores(); + bnusd.transfer(router._address(), BigInteger.valueOf(100000).multiply(EXA), null); + bnusd.transfer(Address.fromString(prepWallet2.getAddress().toString()), BigInteger.valueOf(1000).multiply(EXA), null); + System.out.println(bnusd.balanceOf(router._address())); + } + + void setDexScore(){ +// setScores(); + sicx.transfer(dex._address(), BigInteger.valueOf(100000).multiply(EXA), null); + System.out.println(sicx.balanceOf(dex._address())); + } + + private void registerPrepMethod(){ + setInitialBlockMethod(); + cpsMain.toggle_maintenance(); + prepSender1.register_prep(); + prepSender2.register_prep(); + prepSender3.register_prep(); + prepSender4.register_prep(); + prepSender5.register_prep(); + prepSender6.register_prep(); + prepSender7.register_prep(); + } + + @Test + @Order(2) + void submitProposal(){ + setCPFTreasuryContract(); + registerPrepMethod(); + ProposalAttributes proposalAttributes = new ProposalAttributes(); + proposalAttributes.ipfs_hash = "Proposal 1"; + proposalAttributes.project_title = "Proposal 1 title"; + proposalAttributes.ipfs_link = "Link"; + proposalAttributes.project_duration = 3; + proposalAttributes.token = "bnUSD"; + proposalAttributes.sponsor_address = Address.fromString(prepWallet2.getAddress().toString()); + proposalAttributes.total_budget = BigInteger.valueOf(100); + + cpsMain.submit_proposal(BigInteger.valueOf(50).multiply(EXA), proposalAttributes); + + Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); + assertEquals(proposalDetails.get("ipfs_hash"), "Proposal 1"); + assertEquals(proposalDetails.get("project_duration"), "0x" + Integer.toHexString(3)); + assertEquals(proposalDetails.get("project_title"), "Proposal 1 title"); + assertEquals(proposalDetails.get("status"), "_sponsor_pending"); + assertEquals(proposalDetails.get("token"), "bnUSD"); + String totalBudgetString = ((String) proposalDetails.get("total_budget")).substring(2); + assertEquals(new BigInteger(totalBudgetString, 16), BigInteger.valueOf(100).multiply(EXA)); + } + + @Test + @Order(3) + void voteProposal(){ + JsonObject sponsorVoteParams = new JsonObject(); + sponsorVoteParams.add("method", "sponsor_vote"); + JsonObject params = new JsonObject(); + params.add("ipfs_hash", "Proposal 1"); + params.add("vote", "_accept"); + params.add("vote_reason", "sponsor_reason"); + sponsorVoteParams.add("params", params); + logger("sponsor vote start"); + bnUSDSender2.transfer(cpsMain._address(), BigInteger.valueOf(10).multiply(EXA), sponsorVoteParams.toString().getBytes()); + logger("sponosr vote complete"); + + cpsMain.update_next_block(0); + logger("period ended"); + + cpsMain.update_period(); + logger("updated to next period"); + + prepSender1.vote_proposal("Proposal 1", "_approve", "reason", false); + prepSender2.vote_proposal("Proposal 1", "_approve", "reason", false); + prepSender3.vote_proposal("Proposal 1", "_approve", "reason", false); + prepSender4.vote_proposal("Proposal 1", "_approve", "reason", false); + prepSender5.vote_proposal("Proposal 1", "_approve", "reason", false); + prepSender6.vote_proposal("Proposal 1", "_reject", "reason", false); + prepSender7.vote_proposal("Proposal 1", "_reject", "reason", false); + + logger("completed vote"); + + Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); + logger(proposalDetails); + + assertEquals("0x" + Integer.toHexString(5), proposalDetails.get("approve_voters")); + assertEquals("0x" + Integer.toHexString(2), proposalDetails.get("reject_voters")); + assertEquals("0x" + Integer.toHexString(7), proposalDetails.get("total_voters")); + assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String) proposalDetails.get("approved_votes")).substring(2), 16)); + assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String) proposalDetails.get("rejected_votes")).substring(2), 16)); + assertEquals(BigInteger.valueOf(5600).multiply(EXA), new BigInteger(((String) proposalDetails.get("total_votes")).substring(2), 16)); + } + + @Test + @Order(4) + void votePriority(){ + String[] priorityVote = {"Proposal 1"}; + logger("priority voting started"); + prepSender1.votePriority(priorityVote); + prepSender2.votePriority(priorityVote); + prepSender3.votePriority(priorityVote); + prepSender4.votePriority(priorityVote); + prepSender5.votePriority(priorityVote); + prepSender6.votePriority(priorityVote); + prepSender7.votePriority(priorityVote); + logger("priority vote complete"); + Map priorityVoteResult = cpsMain.getPriorityVoteResult(); + logger(priorityVoteResult); + assertEquals(7, priorityVoteResult.get("Proposal 1")); + } + + @Test + @Order(5) + void updatePeriodAfterVoting(){ + cpsMain.update_next_block(0); + logger("end period"); + + cpsMain.update_period(); + logger("end first update period period"); + + cpsMain.update_period(); + logger("end second update period period"); + + cpsMain.update_period(); + logger("end third update period period"); + + cpsMain.update_period(); + logger("end fourth update period period"); + + Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); + logger(proposalDetails); + + assertEquals("bond_approved", proposalDetails.get("sponsor_deposit_status")); + assertEquals("_active", proposalDetails.get("status")); + } + + @Test + @Order(6) + void submitProgressReport(){ + ProgressReportAttributes progress = new ProgressReportAttributes(); + progress.ipfs_hash = "Proposal 1"; + progress.report_hash = "Report 1"; + progress.progress_report_title = "Progress Report Title"; + progress.ipfs_link = "Link"; + progress.additional_budget = BigInteger.valueOf(50); + progress.budget_adjustment = Boolean.TRUE; + progress.percentage_completed = 10; + progress.additional_month = 2; + cpsMain.toggleBudgetAdjustmentFeature(); + cpsMain.submit_progress_report(progress); + + Map progressReports = cpsMain.get_progress_reports_by_hash("Report 1"); + logger(progressReports); + + assertEquals("Report 1", progressReports.get("report_hash")); + assertEquals("_waiting", progressReports.get("status")); + assertEquals("Progress Report Title", progressReports.get("progress_report_title")); + assertEquals("Proposal 1", progressReports.get("ipfs_hash")); + assertEquals("_pending", progressReports.get("budget_adjustment_status")); + assertEquals("0x" + Integer.toHexString(2), progressReports.get("additional_month")); + assertEquals(BigInteger.valueOf(50).multiply(EXA), new BigInteger(((String)progressReports.get("additional_budget")).substring(2), 16)); } + @Test + @Order(7) + void vote_progress_report(){ + cpsMain.update_next_block(0); + logger("period ended"); + + logger(cpsMain.get_PReps()); + + cpsMain.update_period(); + logger("updated to next period"); + + logger(cpsMain.get_period_status()); + + prepSender1.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); + prepSender2.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); + prepSender3.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); + prepSender4.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); + prepSender5.vote_progress_report("Proposal 1", "Report 1", "_reject", "vote reason", "_reject", false); + prepSender6.vote_progress_report("Proposal 1", "Report 1", "_reject", "vote reason", "_reject", false); + prepSender7.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); + + logger("completed vote"); + + Map progressReports = cpsMain.get_progress_reports_by_hash("Report 1"); + logger(progressReports); + + assertEquals(BigInteger.valueOf(5600).multiply(EXA), new BigInteger(((String)progressReports.get("total_votes")).substring(2), 16)); + assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String)progressReports.get("approved_votes")).substring(2), 16)); + assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String)progressReports.get("rejected_votes")).substring(2), 16)); + assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String)progressReports.get("budget_approved_votes")).substring(2), 16)); + assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String)progressReports.get("budget_rejected_votes")).substring(2), 16)); + assertEquals("0x" + Integer.toHexString(7), progressReports.get("total_voters")); + assertEquals("0x" + Integer.toHexString(5), progressReports.get("approve_voters")); + assertEquals("0x" + Integer.toHexString(2), progressReports.get("reject_voters")); + assertEquals("0x" + Integer.toHexString(5), progressReports.get("budget_approve_voters")); + assertEquals("0x" + Integer.toHexString(2), progressReports.get("budget_reject_voters")); + } + + @Test + @Order(8) + void update_period_after_voting_progress_reports(){ + cpsMain.update_next_block(0); + logger("end period"); + + cpsMain.update_period(); + logger("end first update period period"); + + cpsMain.update_period(); + logger("end second update period period"); + + cpsMain.update_period(); + logger("end third update period period"); + + cpsMain.update_period(); + logger("end fourth update period period"); + + Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); + logger(proposalDetails); + + Map progressDetails = cpsMain.get_progress_reports_by_hash("Report 1"); + logger(progressDetails); + } + void logger(T log){ + System.out.println(log); + } + + } diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java index 8ac2e7db..ee46165d 100644 --- a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java @@ -1,50 +1,156 @@ package community.icon.cps.score.test.integration; import foundation.icon.icx.KeyWallet; -import foundation.icon.jsonrpc.model.Hash; -import foundation.icon.jsonrpc.model.TransactionResult; +import foundation.icon.icx.data.Bytes; import foundation.icon.score.client.DefaultScoreClient; import community.icon.cps.score.lib.interfaces.CPSTreasuryInterfaceScoreClient; import community.icon.cps.score.lib.interfaces.CPFTreasuryInterfaceScoreClient; +import community.icon.cps.score.lib.interfaces.CPSCoreInterfaceScoreInterface; +import community.icon.cps.score.lib.interfaces.DexInterfaceScoreClient; +import community.icon.cps.score.lib.interfaces.sICXInterfaceScoreClient; +import community.icon.cps.score.lib.interfaces.bnUSDInterfaceScoreClient; +import community.icon.cps.score.lib.interfaces.RouterInterfaceScoreClient; import score.Address; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; import java.math.BigInteger; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.function.Consumer; import static community.icon.cps.score.test.integration.ScoreIntegrationTest.*; + public class CPS { public KeyWallet user; public KeyWallet testUser; public KeyWallet owner; + /* + Prep wallets loaded from test-lib/src/main/java/community/icon/cps/score/test/wallets + */ + + public KeyWallet prepWallet1; + public KeyWallet prepWallet2; + public KeyWallet prepWallet3; + public KeyWallet prepWallet4; + public KeyWallet prepWallet5; + public KeyWallet prepWallet6; + public KeyWallet prepWallet7; + public CPSClient ownerClient; public DefaultScoreClient cpsTreasury; public DefaultScoreClient cpfTreasury; + public DefaultScoreClient cpsCore; + + public DefaultScoreClient dex; + public DefaultScoreClient router; + public DefaultScoreClient bnusd; + public DefaultScoreClient sicx; + + public DefaultScoreClient governanceBalanced; public CPSTreasuryInterfaceScoreClient cpsTreasuryScore; public CPFTreasuryInterfaceScoreClient cpfTreasuryScore; + public CPSCoreInterfaceScoreInterface cpsMainScore; + Map cpsClients; + public List prepList; + public CPS() throws Exception{ cpsClients = new HashMap<>(); owner = createWalletWithBalance(BigInteger.TEN.pow(24)); user = createWalletWithBalance(BigInteger.TEN.pow(24)); testUser = createWalletWithBalance(BigInteger.TEN.pow(24)); + BufferedReader br = new BufferedReader(new FileReader("privateKey.txt")); +// System.out.println("Reading the content of the file in cpsMain: " + br.readLine()); + String longPrivateKey = br.readLine(); + String privateKey0 = longPrivateKey.substring(0, 66); + String privateKey1 = longPrivateKey.substring(66, 132); + String privateKey2 = longPrivateKey.substring(132, 198); + String privateKey3 = longPrivateKey.substring(198, 264); + String privateKey4 = longPrivateKey.substring(264, 330); + String privateKey5 = longPrivateKey.substring(330, 396); + String privateKey6 = longPrivateKey.substring(396, 462); + + prepWallet1 = KeyWallet.load(new Bytes(privateKey1)); + prepWallet2 = KeyWallet.load(new Bytes(privateKey2)); + prepWallet3 = KeyWallet.load(new Bytes(privateKey3)); + prepWallet4 = KeyWallet.load(new Bytes(privateKey4)); + prepWallet5 = KeyWallet.load(new Bytes(privateKey5)); + prepWallet6 = KeyWallet.load(new Bytes(privateKey6)); + prepWallet7 = KeyWallet.load(new Bytes(privateKey0)); } public void setupCPS() throws Exception{ registerPreps(); deployContracts(); +// setStakeOfPreps(); +// setDelegationOfPreps(); +// setBonderListOfPReps(); +// setBondOfPreps(); +// registerGodPrep(); +// setGodStake(); + } + + public void registerGodPrep(){ + registerGodClient(); + } + + public void setGodPrep(){ + setGodStake(); + } + + public void setStakeOfPreps(){ + KeyWallet[] keyWallets = {prepWallet1, prepWallet2, prepWallet3, prepWallet4, prepWallet5, prepWallet6, prepWallet7}; + setStake(keyWallets); + } + + public void setDelegationOfPreps(){ + KeyWallet[] keyWallets = {prepWallet1, prepWallet2, prepWallet3, prepWallet4, prepWallet5, prepWallet6, prepWallet7}; + setDelegation(keyWallets); + } + + public void setBondOfPreps(){ + KeyWallet[] keyWallets = {prepWallet1, prepWallet2, prepWallet3, prepWallet4, prepWallet5, prepWallet6, prepWallet7}; + setBond(keyWallets); + } + + public void setBonderListOfPReps(){ + KeyWallet[] keyWallets = {prepWallet1, prepWallet2, prepWallet3, prepWallet4, prepWallet5, prepWallet6, prepWallet7}; + setBonderList(keyWallets); } public void deployContracts(){ - cpsTreasury = deploy(owner, "CPSTreasury", null); - cpfTreasury = deploy(owner, "CPFTreasury", null); + cpsCore = deploy(owner, "CPSCore", null); + + Map cpsScoreAddress = Map.of("cps_score", cpsCore._address()); + cpsTreasury = deploy(owner, "CPSTreasury", cpsScoreAddress); + cpfTreasury = deploy(owner, "CPFTreasury", cpsScoreAddress); + + + dex = deploy(owner, "Dex", null); + + Map bnUSDParams = Map.of( + "_name", "Balanced Dollar", + "_symbol", "bnUSD", + "_decimals", BigInteger.valueOf(18), + "_initialSupply", BigInteger.valueOf(100000000)); + bnusd = deploy(owner, "bnUSD", bnUSDParams); + + sicx = deploy(owner, "sICX", bnUSDParams); + + router = deploy(owner, "Router", null); + } + + public void setScoreAddresses(){ + // CPS Main } } diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java index 3034ede3..4390c289 100644 --- a/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java @@ -1,7 +1,9 @@ package community.icon.cps.score.test.integration; +import community.icon.cps.score.lib.interfaces.SystemInterface; import foundation.icon.icx.KeyWallet; import foundation.icon.icx.Wallet; +import foundation.icon.icx.data.Bytes; import foundation.icon.jsonrpc.Address; import foundation.icon.jsonrpc.model.Hash; import foundation.icon.jsonrpc.model.TransactionResult; @@ -9,14 +11,20 @@ import foundation.icon.score.client.RevertedException; import community.icon.cps.score.lib.interfaces.SystemInterfaceScoreClient; +import net.bytebuddy.pool.TypePool; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.function.Executable; import score.UserRevertedException; +import java.io.BufferedReader; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.PrintStream; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; +import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.List; @@ -31,6 +39,8 @@ import static community.icon.cps.score.test.integration.Env.Chain; import static community.icon.cps.score.test.integration.Env.getDefaultChain; import static org.junit.jupiter.api.Assertions.assertEquals; +import static community.icon.cps.score.lib.interfaces.SystemInterface.Delegation; +import static community.icon.cps.score.lib.interfaces.SystemInterface.Bond; @Tag("integration") @TestMethodOrder(value = MethodOrderer.OrderAnnotation.class) @@ -41,38 +51,130 @@ public interface ScoreIntegrationTest { DefaultScoreClient client = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, null, null); SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); + public static final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L); @SuppressWarnings("unchecked") static void registerPreps() throws Exception { Map getPreps; + String privateKey = ""; try { - getPreps = systemScore.getPReps(BigInteger.ONE, BigInteger.valueOf(100)); + getPreps = systemScore.getPReps(BigInteger.ONE, BigInteger.valueOf(7)); } catch (Exception e) { - registerPrep(); - getPreps = systemScore.getPReps(BigInteger.ONE, BigInteger.valueOf(100)); + privateKey = registerPrep(); + getPreps = systemScore.getPReps(BigInteger.ONE, BigInteger.valueOf(7)); } List> prepList = (List>) getPreps.get("preps"); int prepCount = prepList.size(); - if (prepCount >= 100) { + if (prepCount >= 7) { return; } - int remainingPrepsToRegister = 100 - prepCount; + int remainingPrepsToRegister = 7 - prepCount; for (int i = 0; i < remainingPrepsToRegister; i++) { - registerPrep(); + privateKey = privateKey + registerPrep(); } + PrintStream out = new PrintStream(new FileOutputStream("privateKey.txt")); + System.out.println("private keys: " + privateKey); + out.println(privateKey); + BufferedReader br = new BufferedReader(new FileReader("privateKey.txt")); + System.out.println("Reading the content of the file: " + br.readLine()); } - private static void registerPrep() throws Exception { + private static String registerPrep() throws Exception { KeyWallet owner = createWalletWithBalance(BigInteger.TEN.pow(24)); + String privateKey = String.valueOf(owner.getPrivateKey()); +// PrintStream out = new PrintStream(new FileOutputStream("privateKey.txt")); +// System.out.println("private keys: " + privateKey); +// out.println(privateKey); DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner, DefaultScoreClient.ZERO_ADDRESS); SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); systemScore.registerPRep(BigInteger.valueOf(2000).multiply(BigInteger.TEN.pow(18)), "test", "kokoa@example.com", "USA", "New York", "https://icon.kokoa.com", "https://icon.kokoa.com/json/details.json", "localhost:9082"); + return privateKey; + } + + public static void registerGodClient() { + systemScore.registerPRep(BigInteger.valueOf(2000).multiply(BigInteger.TEN.pow(18)), "test", + "kokoa@example.com", "USA", "New York", "https://icon.kokoa.com", + "https://icon.kokoa.com/json/details.json", "localhost:9082"); + + } + + public static void registerPrepByPrivateKey(KeyWallet owner){ + DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner, + DefaultScoreClient.ZERO_ADDRESS); + SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); + systemScore.registerPRep(BigInteger.valueOf(2000).multiply(BigInteger.TEN.pow(18)), "test", + "kokoa@example.com", "USA", "New York", "https://icon.kokoa.com", + "https://icon.kokoa.com/json/details.json", "localhost:9082"); + } + + public static void setStake(KeyWallet[] owner) { + for (int i = 0; i < owner.length; i++) { + DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner[i], + DefaultScoreClient.ZERO_ADDRESS); + SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); + systemScore.setStake(BigInteger.valueOf(1000).multiply(EXA)); + } + } + + public static void setGodStake(){ + systemScore.setStake(BigInteger.valueOf(9000000).multiply(EXA)); + Delegation[] delegation = new Delegation[1]; + delegation[0] = new Delegation(); + delegation[0].address = score.Address.fromString(chain.godWallet.getAddress().toString()); + delegation[0].value = BigInteger.valueOf(8000000).multiply(EXA); + systemScore.setDelegation(delegation); + + score.Address[] addresses = new score.Address[1]; + addresses[0] = score.Address.fromString(chain.godWallet.getAddress().toString()); + systemScore.setBonderList(addresses); + + Bond[] bonds = new Bond[1]; + bonds[0] = new Bond(); + bonds[0].address = score.Address.fromString(chain.godWallet.getAddress().toString()); + bonds[0].value = BigInteger.valueOf(1000000).multiply(EXA); + systemScore.setBond(bonds); + } + public static void setDelegation(KeyWallet[] owner){ + for (int i = 0; i < owner.length; i++) { + Delegation[] delegations = new Delegation[1]; + delegations[0] = new Delegation(); + delegations[0].address = score.Address.fromString(owner[i].getAddress().toString()); + delegations[0].value = BigInteger.valueOf(400).multiply(EXA); + DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner[i], + DefaultScoreClient.ZERO_ADDRESS); + SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); + systemScore.setDelegation(delegations); + } + } + + public static void setBond(KeyWallet[] owner) { + for (int i = 0; i < owner.length; i++) { + Bond[] bond = new Bond[1]; + bond[0] = new Bond(); + bond[0].address = score.Address.fromString(owner[i].getAddress().toString()); + bond[0].value = BigInteger.valueOf(400).multiply(EXA); + DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner[i], + DefaultScoreClient.ZERO_ADDRESS); + SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); + systemScore.setBond(bond); + } + } + + public static void setBonderList(KeyWallet[] owner){ + for (int i = 0; i < owner.length; i++) { + score.Address[] bonderList = new score.Address[1]; + bonderList[0] = score.Address.fromString(owner[i].getAddress().toString()); + DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner[i], + DefaultScoreClient.ZERO_ADDRESS); + SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); + systemScore.setBonderList(bonderList); + } } static KeyWallet createWalletWithBalance(BigInteger amount) throws Exception { From ac5d9e73861a84db97f87b4834359196eedf58d9 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 9 Nov 2022 10:51:55 +0545 Subject: [PATCH 065/112] unit tests added for CPSCore score --- .../icon/cps/score/cpscore/CPSScoreTest.java | 1355 +++++++++++++++++ 1 file changed, 1355 insertions(+) create mode 100644 CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java diff --git a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java new file mode 100644 index 00000000..a403ab7c --- /dev/null +++ b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java @@ -0,0 +1,1355 @@ +package community.icon.cps.score.cpscore; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonObject; +import com.eclipsesource.json.JsonValue; +import com.iconloop.score.test.Account; +import com.iconloop.score.test.Score; +import com.iconloop.score.test.ServiceManager; +import com.iconloop.score.test.TestBase; +import com.sun.management.DiagnosticCommandMBean; +import community.icon.cps.score.cpscore.utils.ArrayDBUtils; +import community.icon.cps.score.cpscore.utils.Constants; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import org.mockito.Mock; +import org.mockito.stubbing.Answer; +import score.Address; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static community.icon.cps.score.cpscore.db.ProposalDataDb.rejectVoters; +import static community.icon.cps.score.cpscore.db.ProposalDataDb.sponsorAddress; +import static org.mockito.Mockito.*; + +import score.ArrayDB; +import score.Context; +import score.VarDB; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +import java.math.BigInteger; +import java.nio.channels.MulticastChannel; +import java.security.SecureRandom; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static community.icon.cps.score.cpscore.utils.Constants.*; +import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; +import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; + +public class CPSScoreTest extends TestBase{ + private static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); + public static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000"); + private static final Address cpsTreasury = Address.fromString("cx0000000000000000000000000000000000000002"); + private static final Address cpfTreasury = Address.fromString("cx0000000000000000000000000000000000000003"); + private static final Address bnUSDScore = Address.fromString("cx0000000000000000000000000000000000000004"); + private static final Address dividends = Address.fromString("cx0000000000000000000000000000000000000005"); + private static final Address utap = Address.fromString("cx0000000000000000000000000000000000000006"); + private static final Address rewards = Address.fromString("cx0000000000000000000000000000000000000006"); + + private static final Address dice = Address.fromString("cx0000000000000000000000000000000000000007"); + private static final Address roulette = Address.fromString("cx0000000000000000000000000000000000000008"); + private static final Address blackjack = Address.fromString("cx0000000000000000000000000000000000000009"); + public static final String TAG = "CPS Score"; + public static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); + + private static final ServiceManager sm = getServiceManager(); + private static final Account owner = sm.createAccount(); + private static final Account testingAccount = sm.createAccount(); + private static final Account testingAccount1 = sm.createAccount(); + private static final Account testingAccount2 = sm.createAccount(); + private static final Account testingAccount3 = sm.createAccount(); + private static final Account testingAccount4 = sm.createAccount(); + private static final Account testingAccount5 = sm.createAccount(); + private static final Account testingAccount6 = sm.createAccount(); + private static final Account notRevshareWallet = sm.createAccount(); + public static final BigInteger decimal = new BigInteger("1000000000000000000"); + private Score cpsScore; + private final SecureRandom secureRandom = new SecureRandom(); + private static MockedStatic contextMock; + + CPSCore scoreSpy; + + @BeforeEach + public void setup() throws Exception { + cpsScore = sm.deploy(owner, CPSCore.class); + CPSCore instance = (CPSCore) cpsScore.getInstance(); + scoreSpy = spy(instance); + cpsScore.setInstance(scoreSpy); + long currentTime = System.currentTimeMillis() / 1000L; + sm.getBlock().increase(currentTime / 2); + contextMock.reset(); + } + + @BeforeAll + public static void init(){ + contextMock = Mockito.mockStatic(Context.class, CALLS_REAL_METHODS); + } + + public void expectErrorMessage(Executable contractCall, String errorMessage) { + AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); + assertEquals(errorMessage, e.getMessage()); + } + + @Test + void name(){ + assertEquals(cpsScore.call("name"), TAG); + } + + @Test + void addAdmin(){ + cpsScore.invoke(owner, "add_admin", testingAccount.getAddress()); + assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("get_admins")); + } + + @Test + void addAdminNotOwner(){ + Executable addAdminNotOwner = () -> cpsScore.invoke(testingAccount, "addAdmin", testingAccount.getAddress()); + expectErrorMessage(addAdminNotOwner, "Reverted(0): SenderNotScoreOwner: Sender=" + testingAccount.getAddress() + " Owner=" + owner.getAddress()); + } + + @Test + void removeAdmin(){ + cpsScore.invoke(owner, "add_admin", testingAccount.getAddress()); + assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("getAdmins")); + cpsScore.invoke(owner, "remove_admin", testingAccount.getAddress()); + assertEquals(0, ((List) cpsScore.call("getAdmins")).size()); + } + + @Test + void removeAdminNotOwner(){ + cpsScore.invoke(owner, "addAdmin", testingAccount.getAddress()); + assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("getAdmins")); + Executable removeAdminNotOwner = () -> cpsScore.invoke(testingAccount, "removeAdmin", testingAccount.getAddress()); + expectErrorMessage(removeAdminNotOwner, "Reverted(0): SenderNotScoreOwner: Sender=" + testingAccount.getAddress() + " Owner=" + owner.getAddress()); + } + + @Test + void removeAdminAddressNotAdmin(){ + cpsScore.invoke(owner, "addAdmin", testingAccount.getAddress()); + assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("getAdmins")); + Executable removeAdminNotOwner = () -> cpsScore.invoke(owner, "removeAdmin", testingAccount1.getAddress()); + expectErrorMessage(removeAdminNotOwner, "Reverted(0): CPS Score: Address not registered as admin."); + } + + void addAdminMethod(){ + cpsScore.invoke(owner, "addAdmin", owner.getAddress()); + } + + @Test + void registerPRep(){ + registerPrepsMethod(); + assertEquals(7, ((List)(cpsScore.call("get_PReps"))).size()); + } + + @Test + void registerPrepAlreadyRegistered(){ + List> prepDict = + List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), + Map.of("name", "testingAccount", "address", testingAccount.getAddress(), "power", BigInteger.valueOf(850)), + Map.of("name", "testingAccount1", "address", testingAccount1.getAddress(), "power", BigInteger.valueOf(770)), + Map.of("name", "testingAccount2" , "address", testingAccount2.getAddress(), "power", BigInteger.valueOf(800)), + Map.of("name", "testingAccount3", "address", testingAccount3.getAddress(), "power", BigInteger.valueOf(990)), + Map.of("name", "testingAccount4", "address", testingAccount4.getAddress(), "power", BigInteger.valueOf(500)), + Map.of("name", "testingAccount5", "address", testingAccount5.getAddress(), "power", BigInteger.valueOf(250)) + ); + Map preps = Map.of("preps", prepDict); + + addAdminMethod(); + doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + cpsScore.invoke(owner, "toggle_maintenance"); + cpsScore.invoke(owner, "setInitialBlock"); + cpsScore.invoke(owner, "register_prep"); + Executable register = () -> cpsScore.invoke(owner, "register_prep"); + expectErrorMessage(register, "Reverted(0): CPS Score: P-Rep is already registered."); + } + + @Test + void registerPrepNotAPrep(){ + List> prepDict = + List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), + Map.of("name", "testingAccount", "address", testingAccount.getAddress(), "power", BigInteger.valueOf(850)), + Map.of("name", "testingAccount1", "address", testingAccount1.getAddress(), "power", BigInteger.valueOf(770)), + Map.of("name", "testingAccount2" , "address", testingAccount2.getAddress(), "power", BigInteger.valueOf(800)), + Map.of("name", "testingAccount3", "address", testingAccount3.getAddress(), "power", BigInteger.valueOf(990)), + Map.of("name", "testingAccount4", "address", testingAccount4.getAddress(), "power", BigInteger.valueOf(500)), + Map.of("name", "testingAccount5", "address", testingAccount5.getAddress(), "power", BigInteger.valueOf(250)) + ); + Map preps = Map.of("preps", prepDict); + + addAdminMethod(); + doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + cpsScore.invoke(owner, "toggleMaintenance"); + cpsScore.invoke(owner, "setInitialBlock"); + Executable register = () -> cpsScore.invoke(testingAccount6, "register_prep"); + expectErrorMessage(register, "Reverted(0): CPS Score: Not a P-Rep."); + } + + @Test + void registerPrepPrepInDenyList(){ + ArrayDB
denylist = mock(ArrayDB.class); + denylist.add(owner.getAddress()); + List> prepDict = + List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), + Map.of("name", "testingAccount", "address", testingAccount.getAddress(), "power", BigInteger.valueOf(850)), + Map.of("name", "testingAccount1", "address", testingAccount1.getAddress(), "power", BigInteger.valueOf(770)), + Map.of("name", "testingAccount2" , "address", testingAccount2.getAddress(), "power", BigInteger.valueOf(800)), + Map.of("name", "testingAccount3", "address", testingAccount3.getAddress(), "power", BigInteger.valueOf(990)), + Map.of("name", "testingAccount4", "address", testingAccount4.getAddress(), "power", BigInteger.valueOf(500)), + Map.of("name", "testingAccount5", "address", testingAccount5.getAddress(), "power", BigInteger.valueOf(250)) + ); + Map preps = Map.of("preps", prepDict); + + addAdminMethod(); + doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + cpsScore.invoke(owner, "toggleMaintenance"); + cpsScore.invoke(owner, "setInitialBlock"); +// contextMock.when() + cpsScore.invoke(owner, "register_prep"); + // todo check when voiting logic is achecked + } + + @Test + void unregisterPrep(){ + List> prepDict = + List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), + Map.of("name", "testingAccount", "address", testingAccount.getAddress(), "power", BigInteger.valueOf(850)), + Map.of("name", "testingAccount1", "address", testingAccount1.getAddress(), "power", BigInteger.valueOf(770)), + Map.of("name", "testingAccount2" , "address", testingAccount2.getAddress(), "power", BigInteger.valueOf(800)), + Map.of("name", "testingAccount3", "address", testingAccount3.getAddress(), "power", BigInteger.valueOf(990)), + Map.of("name", "testingAccount4", "address", testingAccount4.getAddress(), "power", BigInteger.valueOf(500)), + Map.of("name", "testingAccount5", "address", testingAccount5.getAddress(), "power", BigInteger.valueOf(250)) + ); + Map preps = Map.of("preps", prepDict); + + addAdminMethod(); + doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + cpsScore.invoke(owner, "toggleMaintenance"); + cpsScore.invoke(owner, "setInitialBlock"); + + cpsScore.invoke(owner, "register_prep"); + assertEquals(1, ((List)(cpsScore.call("getPReps"))).size()); + + Map loginPrep = (Map) cpsScore.call("login_prep", owner.getAddress()); + System.out.println(loginPrep); + assertEquals(BigInteger.ONE, loginPrep.get("isRegistered")); + + cpsScore.invoke(owner, "unregister_prep"); + assertEquals(0, ((List)(cpsScore.call("getPReps"))).size()); + + loginPrep = (Map) cpsScore.call("loginPrep", owner.getAddress()); + System.out.println(loginPrep); + assertEquals(BigInteger.ZERO, loginPrep.get("isRegistered")); + } + + @Test + void unregisterPrepNotInValidPrep(){ + List> prepDict = + List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), + Map.of("name", "testingAccount", "address", testingAccount.getAddress(), "power", BigInteger.valueOf(850)), + Map.of("name", "testingAccount1", "address", testingAccount1.getAddress(), "power", BigInteger.valueOf(770)), + Map.of("name", "testingAccount2" , "address", testingAccount2.getAddress(), "power", BigInteger.valueOf(800)), + Map.of("name", "testingAccount3", "address", testingAccount3.getAddress(), "power", BigInteger.valueOf(990)), + Map.of("name", "testingAccount4", "address", testingAccount4.getAddress(), "power", BigInteger.valueOf(500)), + Map.of("name", "testingAccount5", "address", testingAccount5.getAddress(), "power", BigInteger.valueOf(250)) + ); + Map preps = Map.of("preps", prepDict); + + addAdminMethod(); + doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + cpsScore.invoke(owner, "toggleMaintenance"); + cpsScore.invoke(owner, "setInitialBlock"); + cpsScore.invoke(owner, "register_prep"); + + Executable unregister = () -> cpsScore.invoke(testingAccount1, "unregister_prep"); + expectErrorMessage(unregister, "Reverted(0): P-Rep is not registered yet."); + } + + @Test + void loginPrep(){ + List> prepDict = + List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), + Map.of("name", "testingAccount", "address", testingAccount.getAddress(), "power", BigInteger.valueOf(850)), + Map.of("name", "testingAccount1", "address", testingAccount1.getAddress(), "power", BigInteger.valueOf(770)), + Map.of("name", "testingAccount2" , "address", testingAccount2.getAddress(), "power", BigInteger.valueOf(800)), + Map.of("name", "testingAccount3", "address", testingAccount3.getAddress(), "power", BigInteger.valueOf(990)), + Map.of("name", "testingAccount4", "address", testingAccount4.getAddress(), "power", BigInteger.valueOf(500)), + Map.of("name", "testingAccount5", "address", testingAccount5.getAddress(), "power", BigInteger.valueOf(250)) + ); + Map preps = Map.of("preps", prepDict); + + addAdminMethod(); + doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + cpsScore.invoke(owner, "toggleMaintenance"); + cpsScore.invoke(owner, "setInitialBlock"); + cpsScore.invoke(owner, "register_prep"); + + Map loginPrep = (Map) cpsScore.call("loginPrep", owner.getAddress()); + assertEquals(BigInteger.ONE, loginPrep.get("isPRep")); + assertEquals(BigInteger.ONE, loginPrep.get("isRegistered")); + assertEquals(BigInteger.ZERO, loginPrep.get("payPenalty")); + assertEquals(BigInteger.ONE, loginPrep.get("votingPRep")); + + loginPrep = (Map) cpsScore.call("loginPrep", testingAccount.getAddress()); + assertEquals(BigInteger.ONE, loginPrep.get("isPRep")); + assertEquals(BigInteger.ZERO, loginPrep.get("isRegistered")); + assertEquals(BigInteger.ZERO, loginPrep.get("payPenalty")); + assertEquals(BigInteger.ZERO, loginPrep.get("votingPRep")); + + loginPrep = (Map) cpsScore.call("loginPrep", testingAccount6.getAddress()); + assertEquals(BigInteger.ZERO, loginPrep.get("isPRep")); + assertEquals(BigInteger.ZERO, loginPrep.get("isRegistered")); + assertEquals(BigInteger.ZERO, loginPrep.get("payPenalty")); + assertEquals(BigInteger.ZERO, loginPrep.get("votingPRep")); + + } + + @Test + void getPeriodStatus(){ + Map periodStatus = (Map) cpsScore.call("getPeriodStatus"); + assertEquals("None", periodStatus.get("previous_period_name")); + assertEquals("None", periodStatus.get("period_name")); + assertEquals(BigInteger.ZERO, periodStatus.get("next_block")); + assertEquals(BigInteger.ZERO, periodStatus.get("remaining_time")); + assertEquals(BigInteger.valueOf(1293600), periodStatus.get("period_span")); + + List> prepDict = + List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), + Map.of("name", "testingAccount", "address", testingAccount.getAddress(), "power", BigInteger.valueOf(850)), + Map.of("name", "testingAccount1", "address", testingAccount1.getAddress(), "power", BigInteger.valueOf(770)), + Map.of("name", "testingAccount2" , "address", testingAccount2.getAddress(), "power", BigInteger.valueOf(800)), + Map.of("name", "testingAccount3", "address", testingAccount3.getAddress(), "power", BigInteger.valueOf(990)), + Map.of("name", "testingAccount4", "address", testingAccount4.getAddress(), "power", BigInteger.valueOf(500)), + Map.of("name", "testingAccount5", "address", testingAccount5.getAddress(), "power", BigInteger.valueOf(250)) + ); + Map preps = Map.of("preps", prepDict); + + addAdminMethod(); + doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + cpsScore.invoke(owner, "toggleMaintenance"); + cpsScore.invoke(owner, "setInitialBlock"); + + periodStatus = (Map) cpsScore.call("getPeriodStatus"); + assertEquals("None", periodStatus.get("previous_period_name")); + assertEquals(APPLICATION_PERIOD, periodStatus.get("period_name")); + assertEquals(BigInteger.valueOf(1293600), periodStatus.get("period_span")); + System.out.println(periodStatus); + assertEquals(BigInteger.valueOf(Context.getBlockHeight()).add(BLOCKS_DAY_COUNT.multiply(DAY_COUNT)), periodStatus.get("next_block")); + } + + void setScoresMethod(){ + cpsScore.invoke(owner, "addAdmin", owner.getAddress()); + cpsScore.invoke(owner, "setCpsTreasuryScore", cpsTreasury); + cpsScore.invoke(owner, "setCpfTreasuryScore", cpfTreasury); + cpsScore.invoke(owner, "setBnusdScore", bnUSDScore); + + } + private void registerPrepsMethod(){ + setScoresMethod(); + List> prepDict = + List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), + Map.of("name", "testingAccount", "address", testingAccount.getAddress(), "power", BigInteger.valueOf(850)), + Map.of("name", "testingAccount1", "address", testingAccount1.getAddress(), "power", BigInteger.valueOf(770)), + Map.of("name", "testingAccount2" , "address", testingAccount2.getAddress(), "power", BigInteger.valueOf(800)), + Map.of("name", "testingAccount3", "address", testingAccount3.getAddress(), "power", BigInteger.valueOf(990)), + Map.of("name", "testingAccount4", "address", testingAccount4.getAddress(), "power", BigInteger.valueOf(500)), + Map.of("name", "testingAccount5", "address", testingAccount5.getAddress(), "power", BigInteger.valueOf(250)) + ); + Map preps = Map.of("preps", prepDict); + + addAdminMethod(); + doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + cpsScore.invoke(owner, "toggleMaintenance"); + cpsScore.invoke(owner, "setInitialBlock"); + cpsScore.invoke(owner, "register_prep"); + cpsScore.invoke(testingAccount, "register_prep"); + cpsScore.invoke(testingAccount1, "register_prep"); + cpsScore.invoke(testingAccount2, "register_prep"); + cpsScore.invoke(testingAccount3, "register_prep"); + cpsScore.invoke(testingAccount4, "register_prep"); + cpsScore.invoke(testingAccount5, "register_prep"); + } + + + @Test + void submitProposal(){ + submitProposalMethod(); + Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", "Proposal 1"); + System.out.println(proposalDetails); + assertEquals("Proposal 1", proposalDetails.get("ipfs_hash")); + assertEquals("Title", proposalDetails.get("project_title")); + assertEquals(2, proposalDetails.get("project_duration")); + assertEquals(testingAccount.getAddress(), proposalDetails.get("sponsor_address")); + assertEquals(owner.getAddress(), proposalDetails.get("contributor_address")); + assertEquals("_sponsor_pending", proposalDetails.get("status")); + assertEquals(BigInteger.valueOf(100).multiply(MULTIPLIER), proposalDetails.get("total_budget")); + Map proposalDetailsOfStatus = (Map) cpsScore.call("getProposalDetails", SPONSOR_PENDING, owner.getAddress(), 0, 20); + assertEquals(1, proposalDetailsOfStatus.get(COUNT)); + assertEquals(proposalDetails, ((List>)proposalDetailsOfStatus.get(DATA)).get(0)); + + Map proposalDetailsOfWallet = (Map) cpsScore.call("get_proposal_detail_by_wallet", owner.getAddress()); + assertEquals(proposalDetails, ((List>)proposalDetailsOfWallet.get(DATA)).get(0)); + assertEquals(1, proposalDetailsOfWallet.get(COUNT)); + + List proposalKeys = (List) cpsScore.call("getProposalKeys"); + assertEquals(List.of("Proposal 1"), proposalKeys); + } + + void submitProposalMethod(){ + registerPrepsMethod(); + ProposalAttributes proposalAttributes = new ProposalAttributes(); + proposalAttributes.ipfs_hash = "Proposal 1"; + proposalAttributes.project_title = "Title"; + proposalAttributes.project_duration = 2; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = testingAccount.getAddress(); + proposalAttributes.ipfs_link = "link"; + + Map remainingSwapAmount = Map.of( + "remaining_swap_amount", BigInteger.valueOf(1000).multiply(MULTIPLIER), + "maxCap", BigInteger.valueOf(1000).multiply(MULTIPLIER)); + doReturn(remainingSwapAmount).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_remaining_swap_amount")); + contextMock.when(() -> Context.getValue()).thenReturn(BigInteger.valueOf(50).multiply(MULTIPLIER)); + byte [] tx_hash = "transaction".getBytes(); + contextMock.when(() -> Context.getTransactionHash()).thenReturn(tx_hash); + doNothing().when(scoreSpy).callScore(eq(BigInteger.valueOf(25).multiply(MULTIPLIER)), eq(SYSTEM_ADDRESS), eq("burn")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(0)); + cpsScore.invoke(owner, "submitProposal", proposalAttributes); + + } + + @Test + void sponsorVote(){ + submitAndSponsorVote(); + Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", "Proposal 1"); + System.out.println(proposalDetails); + assertEquals(PENDING, proposalDetails.get("status")); + assertEquals(BOND_RECEIVED, proposalDetails.get("sponsor_deposit_status")); + Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); + Map> amount = Map.of( + AMOUNT, Map.of( + Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) + ) + ); + assertEquals(amount, (projectAmounts.get(PENDING))); + + Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); + System.out.println("Sponsors request" + sponosrsRequest); + } + + void submitAndSponsorVote(){ + submitProposalMethod(); + contextMock.when(caller()).thenReturn(bnUSDScore); + JsonObject sponsorVoteParams = new JsonObject(); + sponsorVoteParams.add("method", "sponsor_vote"); + JsonObject params = new JsonObject(); + params.add(IPFS_HASH, "Proposal 1"); + params.add(VOTE, ACCEPT); + params.add(VOTE_REASON, "reason"); + sponsorVoteParams.add("params", params); + + cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), BigInteger.valueOf(10).multiply(MULTIPLIER), sponsorVoteParams.toString().getBytes()); + } + + void updateNextBlock(){ + cpsScore.invoke(owner, "updateNextBlock", 0); + } + + @Test + @DisplayName("vote approve then change it to reject") + void voteProposal(){ + submitAndSponsorVote(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + cpsScore.invoke(owner, "update_period"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", false); + Map proposalDetails = getProposalDetailsByHash("Proposal 1"); + + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("approved_votes")); + assertEquals(1, proposalDetails.get("approve_voters")); + assertEquals(BigInteger.ZERO, proposalDetails.get("rejected_votes")); + assertEquals(0, proposalDetails.get("reject_voters")); + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("total_votes")); + + cpsScore.invoke(owner, "voteProposal", "Proposal 1", REJECT, "reason", true); + + proposalDetails = getProposalDetailsByHash("Proposal 1"); + + assertEquals(BigInteger.valueOf(0), proposalDetails.get("approved_votes")); + assertEquals(0, proposalDetails.get("approve_voters")); + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("rejected_votes")); + assertEquals(1, proposalDetails.get("reject_voters")); + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("total_votes")); + + assertEquals(1, cpsScore.call("checkChangeVote", owner.getAddress(), "Proposal 1", "proposal")); + + Map voteResult = (Map) cpsScore.call("getVoteResult", "Proposal 1"); + System.out.println(voteResult); + } + + @Test + @DisplayName("vote reject then change it to approve") + void voteProposal2(){ + submitAndSponsorVote(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + cpsScore.invoke(owner, "update_period"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + cpsScore.invoke(owner, "voteProposal", "Proposal 1", REJECT, "reason", false); + Map proposalDetails = getProposalDetailsByHash("Proposal 1"); + + assertEquals(BigInteger.valueOf(0), proposalDetails.get("approved_votes")); + assertEquals(0, proposalDetails.get("approve_voters")); + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("rejected_votes")); + assertEquals(1, proposalDetails.get("reject_voters")); + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("total_votes")); + + + cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", true); + proposalDetails = getProposalDetailsByHash("Proposal 1"); + + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("approved_votes")); + assertEquals(1, proposalDetails.get("approve_voters")); + assertEquals(BigInteger.ZERO, proposalDetails.get("rejected_votes")); + assertEquals(0, proposalDetails.get("reject_voters")); + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("total_votes")); + + assertEquals(1, cpsScore.call("checkChangeVote", owner.getAddress(), "Proposal 1", "proposal")); + } + + void voteProposalMethod(){ + submitAndSponsorVote(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + cpsScore.invoke(owner, "update_period"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + String[] proposal = new String[1]; + proposal[0] = "Proposal 1"; + cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + } + + void voteProposalMethodReject(){ + submitAndSponsorVote(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + cpsScore.invoke(owner, "update_period"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + String[] proposal = new String[1]; + proposal[0] = "Proposal 1"; + cpsScore.invoke(owner, "voteProposal", "Proposal 1", REJECT, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProposal", "Proposal 1", REJECT, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProposal", "Proposal 1", REJECT, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProposal", "Proposal 1", REJECT, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProposal", "Proposal 1", REJECT, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProposal", "Proposal 1", REJECT, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProposal", "Proposal 1", REJECT, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + } + + void updatePeriods(){ + // 1/4 + cpsScore.invoke(owner, "update_period"); + // 2/4 + cpsScore.invoke(owner, "update_period"); + // 3/4 + cpsScore.invoke(owner, "update_period"); + // 4/4 + cpsScore.invoke(owner, "update_period"); + } + + @Test + void updatePeriodAfterProposalVoting(){ + voteProposalMethod(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + Map totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + updatePeriods(); + + Map proposalDetails = getProposalDetailsByHash("Proposal 1"); + List> activeProposals = (List>) cpsScore.call("getActiveProposals"); + assertEquals(ACTIVE, proposalDetails.get("status")); + assertEquals(List.of(proposalDetails), activeProposals); + + Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); + System.out.println("Sponsors request" + sponosrsRequest); + + Map sponsorsRecord = (Map) cpsScore.call("getSponsorsRecord"); + assertEquals(1, sponsorsRecord.get(testingAccount.getAddress().toString())); + + Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); + Map> amount = Map.of( + AMOUNT, Map.of( + Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) + ) + ); + assertEquals(amount, (projectAmounts.get(ACTIVE))); + + Map voteResult = (Map) cpsScore.call("getVoteResult", "Proposal 1"); + System.out.println("voteResult: " + voteResult); + } + + @Test + void rejectProposal(){ + voteProposalMethodReject(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + Map totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + contextMock.when(() -> Context.transfer(any(), any())).thenAnswer((Answer) invocation -> null); + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); + updatePeriods(); + + Map proposalDetails = getProposalDetailsByHash("Proposal 1"); + assertEquals(REJECTED, proposalDetails.get("status")); + + Map claimableSponsorBond = (Map) cpsScore.call("checkClaimableSponsorBond", testingAccount.getAddress()); + assertEquals(BigInteger.valueOf(10).multiply(MULTIPLIER), claimableSponsorBond.get(bnUSD)); + + Map voteResult = (Map) cpsScore.call("getVoteResult", "Proposal 1"); + System.out.println("voteResult: " + voteResult); + + List> proposalsHistory = (List>) cpsScore.call("getProposalsHistory"); + assertEquals(proposalDetails, proposalsHistory.get(0)); + } + + @Test + void submitProgressReport(){ + ProgressReportAttributes progressReport = new ProgressReportAttributes(); + progressReport.ipfs_hash = "Proposal 1"; + progressReport.report_hash = "Report 1"; + progressReport.ipfs_link = "Link"; + progressReport.progress_report_title = "Progress Report Title"; + progressReport.budget_adjustment = true; + progressReport.additional_budget = BigInteger.valueOf(10); + progressReport.additional_month = 1; + progressReport.percentage_completed = 50; + updatePeriodAfterProposalVoting(); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), any()); + cpsScore.invoke(owner, "toggleBudgetAdjustmentFeature"); + cpsScore.invoke(owner, "submitProgressReport", progressReport); + + @SuppressWarnings("unchecked") + Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + + assertEquals(progressReport.ipfs_hash, progressReportDetails.get("ipfs_hash")); + assertEquals(progressReport.report_hash, progressReportDetails.get("report_hash")); + assertEquals(progressReport.ipfs_link, progressReportDetails.get("ipfs_link")); + assertEquals(progressReport.progress_report_title, progressReportDetails.get("progress_report_title")); + assertEquals(progressReport.budget_adjustment, progressReportDetails.get("budget_adjustment")); + assertEquals(progressReport.additional_budget.multiply(MULTIPLIER), progressReportDetails.get("additional_budget")); + assertEquals(progressReport.additional_month, progressReportDetails.get("additional_month")); + assertEquals(progressReport.percentage_completed, progressReportDetails.get("percentage_completed")); + + List progressKeys = (List) cpsScore.call("getProgressKeys"); + assertEquals(List.of("Report 1"), progressKeys); + + Map progressReports = (Map) cpsScore.call("getProgressReports", WAITING, 0, 20); + assertEquals(List.of(progressReportDetails), progressReports.get(DATA)); + assertEquals(1, progressReports.get(COUNT)); + + Map progressReportsByProposal = (Map) cpsScore.call("getProgressReportsByProposal", "Proposal 1"); + assertEquals(List.of(progressReportDetails), progressReportsByProposal.get(DATA)); + assertEquals(1, progressReportsByProposal.get(COUNT)); + } + + @Test + void voteProgressReport(){ + submitProgressReport(); + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + + @SuppressWarnings("unchecked") + Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + + assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); + assertEquals(7, progressReportDetails.get(BUDGET_APPROVE_VOTERS)); + assertEquals(7, progressReportDetails.get(APPROVE_VOTERS)); + + Map voteResult = (Map) cpsScore.call("getProgressReportResult", "Report 1"); + System.out.println("progress report vote Result: " + voteResult); + } + + @Test + void voteProgressReportVoteChangeFromApproveToReject(){ + submitProgressReport(); + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + + cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + + Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + + assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(APPROVED_VOTES)); + assertEquals(BigInteger.valueOf(0), progressReportDetails.get(REJECTED_VOTES)); + assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(BUDGET_APPROVED_VOTES)); + assertEquals(BigInteger.valueOf(0), progressReportDetails.get(BUDGET_REJECTED_VOTES)); + assertEquals(1, progressReportDetails.get(APPROVE_VOTERS)); + assertEquals(0, progressReportDetails.get(REJECT_VOTERS)); + assertEquals(1, progressReportDetails.get(BUDGET_APPROVE_VOTERS)); + assertEquals(0, progressReportDetails.get(BUDGET_REJECT_VOTERS)); + + + cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", REJECT, true); + + progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + assertEquals(BigInteger.valueOf(0), progressReportDetails.get(APPROVED_VOTES)); + assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(REJECTED_VOTES)); + assertEquals(BigInteger.valueOf(0), progressReportDetails.get(BUDGET_APPROVED_VOTES)); + assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(BUDGET_REJECTED_VOTES)); + assertEquals(0, progressReportDetails.get(APPROVE_VOTERS)); + assertEquals(1, progressReportDetails.get(REJECT_VOTERS)); + assertEquals(0, progressReportDetails.get(BUDGET_APPROVE_VOTERS)); + assertEquals(1, progressReportDetails.get(BUDGET_REJECT_VOTERS)); + + assertEquals(1, cpsScore.call("checkChangeVote", owner.getAddress(), "Report 1", "progress_reports")); + } + + @Test + void updatePeriodAfterProgressReportSubmission(){ + voteProgressReport(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + Map totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); + updatePeriods(); + + @SuppressWarnings("unchecked") + Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + System.out.println(progressReportDetails); + + assertEquals(APPROVED, progressReportDetails.get(STATUS)); + assertEquals(APPROVED, progressReportDetails.get(BUDGET_ADJUSTMENT_STATUS)); + } + + @Test + void submitProgressReportWithoutBudgetAdjustment(){ + ProgressReportAttributes progressReport = new ProgressReportAttributes(); + progressReport.ipfs_hash = "Proposal 1"; + progressReport.report_hash = "Report 1"; + progressReport.ipfs_link = "Link"; + progressReport.progress_report_title = "Progress Report Title"; + progressReport.budget_adjustment = false; + progressReport.additional_budget = BigInteger.valueOf(0); + progressReport.additional_month = 0; + progressReport.percentage_completed = 50; + updatePeriodAfterProposalVoting(); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), any()); + cpsScore.invoke(owner, "toggleBudgetAdjustmentFeature"); + cpsScore.invoke(owner, "submitProgressReport", progressReport); + } + + @Test + void voteProgressReportAfterSubmittingProposalWithoutBudgetAdjustment(){ + submitProgressReportWithoutBudgetAdjustment(); + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + + @SuppressWarnings("unchecked") + Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + + assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); + assertEquals(7, progressReportDetails.get(APPROVE_VOTERS)); + + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + Map totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); + updatePeriods(); + + progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + System.out.println(progressReportDetails); + + ProgressReportAttributes progressReport = new ProgressReportAttributes(); + progressReport.ipfs_hash = "Proposal 1"; + progressReport.report_hash = "Report 2"; + progressReport.ipfs_link = "Link"; + progressReport.progress_report_title = "Progress Report Title"; + progressReport.budget_adjustment = false; + progressReport.additional_budget = BigInteger.valueOf(0); + progressReport.additional_month = 0; + progressReport.percentage_completed = 50; + + cpsScore.invoke(owner, "submitProgressReport", progressReport); + + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + + progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + + assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); + assertEquals(7, progressReportDetails.get(APPROVE_VOTERS)); + + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); + updatePeriods(); + + Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", "Proposal 1"); + assertEquals(COMPLETED, proposalDetails.get("status")); + + Map sponsorsRecord = (Map) cpsScore.call("getSponsorsRecord"); + assertEquals(1, sponsorsRecord.get(testingAccount.getAddress().toString())); + + Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); + System.out.println("Project Amount: " + projectAmounts); + Map> amount = Map.of( + AMOUNT, Map.of( + Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) + ) + ); + assertEquals(amount, (projectAmounts.get(COMPLETED))); + + Map progressReportsByProposal = (Map) cpsScore.call("getProgressReportsByProposal", "Proposal 1"); + assertEquals(2, progressReportsByProposal.get(COUNT)); + + Map claimableSponsorBond = (Map) cpsScore.call("checkClaimableSponsorBond", testingAccount.getAddress()); + assertEquals(BigInteger.valueOf(10).multiply(MULTIPLIER), claimableSponsorBond.get(bnUSD)); + + List> proposalsHistory = (List>) cpsScore.call("getProposalsHistory"); + assertEquals(proposalDetails, proposalsHistory.get(0)); + } + + @Test + void claimSponsorBond(){ + voteProgressReportAfterSubmittingProposalWithoutBudgetAdjustment(); + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(testingAccount.getAddress()), eq(BigInteger.valueOf(10).multiply(MULTIPLIER))); + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "claimSponsorBond"); + Map claimableSponsorBond = (Map) cpsScore.call("checkClaimableSponsorBond", testingAccount.getAddress()); + assertEquals(BigInteger.valueOf(0), claimableSponsorBond.get(bnUSD)); + + } + + @Test + void sortPriorityProposals(){ + voteProposalMethod(); + @SuppressWarnings("unchecked") + List proposalList = (List) cpsScore.call("sortPriorityProposals"); + assertEquals(List.of("Proposal 1"), proposalList); + + @SuppressWarnings("unchecked") + Map priorityVoteResult = (Map) cpsScore.call("getPriorityVoteResult"); + assertEquals(Map.of("Proposal 1", 7), priorityVoteResult); + } + + @Test + void setCpsTreasury(){ + contextMock.when(caller()).thenReturn(owner.getAddress()); + addAdminMethod(); + cpsScore.invoke(owner, "set_cps_treasury_score", cpsTreasury); + assertEquals(cpsTreasury, cpsScore.call("get_cps_treasury_score")); + } + + @Test + void setCpfTreasury(){ + addAdminMethod(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + cpsScore.invoke(owner, "set_cpf_treasury_score", cpfTreasury); + assertEquals(cpfTreasury, cpsScore.call("get_cpf_treasury_score")); + } + + @Test + void setbnUSDScore(){ + addAdminMethod(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + cpsScore.invoke(owner, "set_bnUSD_score", bnUSDScore); + assertEquals(bnUSDScore, cpsScore.call("get_bnUSD_score")); + } + + @Test + void toggleMaintenanceMode(){ + addAdminMethod(); + cpsScore.invoke(owner, "toggleMaintenance"); + assertEquals(Boolean.FALSE, cpsScore.call("getMaintenanceMode")); + } + + @Test + void payPrepPenalty(){ + submitAndSponsorVote(); + BigInteger[] penaltyAmount = new BigInteger[3]; + penaltyAmount[0] = BigInteger.valueOf(5); + penaltyAmount[1] = BigInteger.valueOf(10); + penaltyAmount[2] = BigInteger.valueOf(15); + contextMock.when(caller()).thenReturn(owner.getAddress()); + cpsScore.invoke(owner, "set_prep_penalty_amount", (Object) penaltyAmount); + updateNextBlock(); + cpsScore.invoke(owner, "update_period"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + String[] proposal = new String[1]; + proposal[0] = "Proposal 1"; + cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + Map totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + updatePeriods(); + + Map proposalDetails = getProposalDetailsByHash("Proposal 1"); + + + @SuppressWarnings("unchecked") + List
denyList = (List
) cpsScore.call("get_denylist"); + assertEquals(List.of(testingAccount5.getAddress()), denyList); + + @SuppressWarnings("unchecked") + Map loginPrep = (Map) cpsScore.call("loginPrep", testingAccount5.getAddress()); + System.out.println(loginPrep); + + JsonObject payPenalty = new JsonObject(); + payPenalty.add("method", "pay_prep_penalty"); + JsonObject params = new JsonObject(); + payPenalty.add("params", params); + + JsonObject burnTokens = new JsonObject(); + burnTokens.add("method", "burn_amount"); + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(new BigInteger("1250000000000000000")), eq(burnTokens.toString().getBytes())); + contextMock.when(caller()).thenReturn(bnUSDScore); + cpsScore.invoke(owner, "tokenFallback", testingAccount5.getAddress(), new BigInteger("1250000000000000000"), payPenalty.toString().getBytes()); + } + + @Test + void disqualifyProposal(){ + updatePeriodAfterProposalVoting(); + updateNextBlock(); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("disqualify_project"), eq("Proposal 1")); + + JsonObject disqualifyProject = new JsonObject(); + disqualifyProject.add("method", "burn_amount"); + JsonObject params = new JsonObject(); + params.add(SPONSOR_ADDRESS, testingAccount.getAddress().toString()); + disqualifyProject.add("params", params); + + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(disqualifyProject.toString().getBytes())); + cpsScore.invoke(owner, "update_period"); + Map proposalDetails = getProposalDetailsByHash("Proposal 1"); + assertEquals(PAUSED, proposalDetails.get(STATUS)); + + Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); + System.out.println("Sponsors request::" + sponosrsRequest); + + Map sponsorsRecord = (Map) cpsScore.call("getSponsorsRecord"); + assertEquals(1, sponsorsRecord.get(testingAccount.getAddress().toString())); + + Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); + Map> amount = Map.of( + AMOUNT, Map.of( + Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) + ) + ); + assertEquals(amount, (projectAmounts.get(PAUSED))); + + updateNextBlock(); + cpsScore.invoke(owner, "update_period"); + proposalDetails = getProposalDetailsByHash("Proposal 1"); + assertEquals(DISQUALIFIED, proposalDetails.get(STATUS)); + assertEquals(BOND_CANCELLED, proposalDetails.get(SPONSOR_DEPOSIT_STATUS)); + + projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); + amount = Map.of( + AMOUNT, Map.of( + Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) + ) + ); + assertEquals(amount, (projectAmounts.get(DISQUALIFIED))); + + List> proposalsHistory = (List>) cpsScore.call("getProposalsHistory"); + assertEquals(proposalDetails, proposalsHistory.get(0)); + } + + @Test + void getContributors(){ + submitAndSponsorVote(); + @SuppressWarnings("unchecked") + List
contributors = (List
) cpsScore.call("getContributors"); + assertEquals(List.of(owner.getAddress()), contributors); + } + + @Test + void rejectSponsorVote(){ + submitProposalMethod(); + contextMock.when(caller()).thenReturn(bnUSDScore); + contextMock.when(() -> Context.transfer(any(), any())).thenAnswer((Answer) invocation -> null); + JsonObject sponsorVoteParams = new JsonObject(); + sponsorVoteParams.add("method", "sponsor_vote"); + JsonObject params = new JsonObject(); + params.add(IPFS_HASH, "Proposal 1"); + params.add(VOTE, REJECT); + params.add(VOTE_REASON, "reason"); + sponsorVoteParams.add("params", params); + + cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), BigInteger.valueOf(0), sponsorVoteParams.toString().getBytes()); + } + + @Test + void disqualifyProjectByRejectingProgressReport(){ + submitProgressReportWithoutBudgetAdjustment(); + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + + JsonObject disqualifyProject = new JsonObject(); + disqualifyProject.add("method", "burn_amount"); + JsonObject params = new JsonObject(); + params.add(SPONSOR_ADDRESS, testingAccount.getAddress().toString()); + disqualifyProject.add("params", params); + + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(disqualifyProject.toString().getBytes())); + cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + + @SuppressWarnings("unchecked") + Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + + assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); + assertEquals(7, progressReportDetails.get(REJECT_VOTERS)); + + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + Map totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); + updatePeriods(); + + progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + System.out.println(progressReportDetails); + + ProgressReportAttributes progressReport = new ProgressReportAttributes(); + progressReport.ipfs_hash = "Proposal 1"; + progressReport.report_hash = "Report 2"; + progressReport.ipfs_link = "Link"; + progressReport.progress_report_title = "Progress Report Title"; + progressReport.budget_adjustment = false; + progressReport.additional_budget = BigInteger.valueOf(0); + progressReport.additional_month = 0; + progressReport.percentage_completed = 50; + + cpsScore.invoke(owner, "submitProgressReport", progressReport); + + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("disqualify_project"), eq("Proposal 1")); + cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + + progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + + assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); + assertEquals(7, progressReportDetails.get(REJECT_VOTERS)); + + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); + updatePeriods(); + + Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", "Proposal 1"); + assertEquals(DISQUALIFIED, proposalDetails.get("status")); + + Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); + System.out.println("Project Amount: " + projectAmounts); + Map> amount = Map.of( + AMOUNT, Map.of( + Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) + ) + ); + assertEquals(amount, (projectAmounts.get(DISQUALIFIED))); + + Map voteResult = (Map) cpsScore.call("getProgressReportResult", "Report 1"); + System.out.println("progress report vote Result of Report 1: " + voteResult); + + voteResult = (Map) cpsScore.call("getProgressReportResult", "Report 2"); + System.out.println("progress report vote Result of Report 2: " + voteResult); + } + + @Test + void setSwapCount(){ + addAdminMethod(); + cpsScore.invoke(owner, "set_swap_count", 10); + assertEquals(10, cpsScore.call("getSwapCount")); + } + + @Test + void fallback(){ + Executable fallback = () -> cpsScore.invoke(owner, "fallback"); + expectErrorMessage(fallback, "Reverted(0): " + "ICX can only be sent while submitting a proposal or paying the penalty."); + } + + @Test + void getPeriodCount(){ + assertEquals(19, cpsScore.call("getPeriodCount")); + } + + + void getPeriodStatusMethod(){ + Map periodStatus = (Map) cpsScore.call("getPeriodStatus"); + + System.out.println(periodStatus); + } + + Map getProposalDetailsByHash(String ipfs_hash){ + return (Map) cpsScore.call("getProposalDetailsByHash", ipfs_hash); + } + public MockedStatic.Verification caller(){ + return () -> Context.getCaller(); + } +} From d3e3f60df2b6509f567934dad2627954ee222979 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Wed, 9 Nov 2022 12:51:46 +0545 Subject: [PATCH 066/112] added dummy scores for integration testing of CPS project --- dummy/Dex/build.gradle | 55 ++++++++ .../src/main/java/dummy/contract/dex/Dex.java | 126 ++++++++++++++++++ dummy/Router/build.gradle | 55 ++++++++ .../java/dummy/contract/router/Router.java | 46 +++++++ dummy/bnUSD/build.gradle | 43 ++++++ .../main/java/dummy/contract/bnusd/bnUSD.java | 28 ++++ dummy/sICX/build.gradle | 43 ++++++ .../main/java/dummy/contract/sicx/sICX.java | 26 ++++ 8 files changed, 422 insertions(+) create mode 100644 dummy/Dex/build.gradle create mode 100644 dummy/Dex/src/main/java/dummy/contract/dex/Dex.java create mode 100644 dummy/Router/build.gradle create mode 100644 dummy/Router/src/main/java/dummy/contract/router/Router.java create mode 100644 dummy/bnUSD/build.gradle create mode 100644 dummy/bnUSD/src/main/java/dummy/contract/bnusd/bnUSD.java create mode 100644 dummy/sICX/build.gradle create mode 100644 dummy/sICX/src/main/java/dummy/contract/sicx/sICX.java diff --git a/dummy/Dex/build.gradle b/dummy/Dex/build.gradle new file mode 100644 index 00000000..bed00959 --- /dev/null +++ b/dummy/Dex/build.gradle @@ -0,0 +1,55 @@ +version = '0.9.1' + +dependencies { + compileOnly 'foundation.icon:javaee-api:0.9.1' + implementation project(':score-lib') + + implementation 'com.github.sink772:javaee-tokens:0.6.1' + implementation 'com.github.sink772:minimal-json:0.9.6' + + testImplementation 'foundation.icon:javaee-unittest:0.9.2' + implementation 'org.mockito:mockito-core:4.3.1' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation('org.mockito:mockito-inline:4.3.1') + implementation 'foundation.icon:javaee-scorex:0.5.2' + +} + +optimizedJar { + mainClassName = 'dummy.contract.dex.Dex' + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +deployJar { + endpoints { + lisbon { + uri = 'https://lisbon.net.solidwallet.io/api/v3' + nid = 0x2 + } + local { + uri = 'http://localhost:9082/api/v3' + nid = 0x3 + } + sejong { + uri = 'https://sejong.net.solidwallet.io/api/v3' + nid = 0x53 + + } + berlin { + uri = 'https://berlin.net.solidwallet.io/api/v3' + nid = 0x7 + to = 'cx28ae7ed3b07ed5247a3d2f97680f8555ce7c0a92' + } + } + keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' + password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' + parameters { + } +} + +test { + useJUnitPlatform() +} diff --git a/dummy/Dex/src/main/java/dummy/contract/dex/Dex.java b/dummy/Dex/src/main/java/dummy/contract/dex/Dex.java new file mode 100644 index 00000000..439f8006 --- /dev/null +++ b/dummy/Dex/src/main/java/dummy/contract/dex/Dex.java @@ -0,0 +1,126 @@ +package dummy.contract.dex; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonObject; +import score.Address; +import score.Context; +import score.DictDB; +import score.VarDB; +import score.annotation.EventLog; +import score.annotation.External; +import scorex.util.ArrayList; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; + +public class Dex implements community.icon.cps.score.lib.interfaces.DexInterface { + private static final String TAG = "Balanced DEX"; + private final VarDB
sicx = Context.newVarDB("sicx", Address.class); + public static final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L); + + public Dex(){} + + @Override + @External + public void setSicxScore(Address _score){ + this.sicx.set(_score); + } + + @External(readonly = true) + public BigInteger getPrice(int poolId){ + return BigInteger.ONE; + } + + @Override + @EventLog + public void Deposit(Address from_token, Address from, BigInteger value){} + + @Override + @EventLog(indexed = 2) + public void Swap(BigInteger _id, Address _baseToken, Address _fromToken, Address _toToken, + Address _sender, Address _receiver, BigInteger _fromValue, BigInteger _toValue, + BigInteger _timestamp, BigInteger _lpFees, BigInteger _balnFees, BigInteger _poolBase, + BigInteger _poolQuote, BigInteger _endingPrice, BigInteger _effectiveFillPrice) { + } + + @Override + @External + public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { + // Parse the transaction data submitted by the user + String unpackedData = new String(_data); + Context.require(!unpackedData.equals(""), "Token Fallback: Data can't be empty"); + if (Arrays.equals(_data, "None".getBytes())){ + return; + } + JsonObject json = Json.parse(unpackedData).asObject(); + + String method = json.get("method").asString(); + Address fromToken = Context.getCaller(); + + Context.require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Invalid token transfer value"); + + // Call an internal method based on the "method" param sent in tokenFallBack + switch (method) { + case "_swap_icx": { + Context.require(fromToken.equals(sicx.get()), + TAG + ": InvalidAsset: _swap_icx can only be called with sICX"); + swapIcx(_from, _value); + break; + + } + case "_swap": { + + // Parse the slippage sent by the user in minimumReceive. + // If none is sent, use the maximum. + JsonObject params = json.get("params").asObject(); + BigInteger minimumReceive = BigInteger.ZERO; + if (params.contains("minimumReceive")) { + minimumReceive = BigInteger.valueOf(1000).multiply(EXA); + Context.require(minimumReceive.signum() >= 0, + TAG + ": Must specify a positive number for minimum to receive"); + } + + // Check if an alternative recipient of the swap is set. + Address receiver; + if (params.contains("receiver")) { + receiver = Address.fromString(params.get("receiver").asString()); + } else { + receiver = _from; + } + + // Get destination coin from the swap + Context.require(params.contains("toToken"), TAG + ": No toToken specified in swap"); + Address toToken = Address.fromString(params.get("toToken").asString()); + + // Perform the swap + exchange(fromToken, toToken, _from, receiver, _value, minimumReceive); + + break; + } + default: + // If no supported method was sent, revert the transaction + Context.revert(100, TAG + ": Unsupported method supplied"); + break; + } + } + + void swapIcx(Address sender, BigInteger value) { + Context.transfer(sender, value); + } + + void exchange(Address fromToken, Address toToken, Address sender, + Address receiver, BigInteger value, BigInteger minimumReceive) { + + if (minimumReceive == null) { + minimumReceive = BigInteger.ZERO; + } + + // Send the trader their funds + Context.call(toToken, "transfer", receiver, value); + + Swap(BigInteger.valueOf(0), fromToken, fromToken, toToken, sender, receiver, value, value, + BigInteger.valueOf(Context.getBlockTimestamp()), BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO + , BigInteger.ZERO); + } +} diff --git a/dummy/Router/build.gradle b/dummy/Router/build.gradle new file mode 100644 index 00000000..3a5641d7 --- /dev/null +++ b/dummy/Router/build.gradle @@ -0,0 +1,55 @@ +version = '0.9.1' + +dependencies { + compileOnly 'foundation.icon:javaee-api:0.9.1' + implementation project(':score-lib') + + implementation 'com.github.sink772:javaee-tokens:0.6.1' + implementation 'com.github.sink772:minimal-json:0.9.6' + + testImplementation 'foundation.icon:javaee-unittest:0.9.2' + implementation 'org.mockito:mockito-core:4.3.1' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation('org.mockito:mockito-inline:4.3.1') + implementation 'foundation.icon:javaee-scorex:0.5.2' + +} + +optimizedJar { + mainClassName = 'dummy.contract.router.Router' + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +deployJar { + endpoints { + lisbon { + uri = 'https://lisbon.net.solidwallet.io/api/v3' + nid = 0x2 + } + local { + uri = 'http://localhost:9082/api/v3' + nid = 0x3 + } + sejong { + uri = 'https://sejong.net.solidwallet.io/api/v3' + nid = 0x53 + + } + berlin { + uri = 'https://berlin.net.solidwallet.io/api/v3' + nid = 0x7 + to = 'cx28ae7ed3b07ed5247a3d2f97680f8555ce7c0a92' + } + } + keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' + password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' + parameters { + } +} + +test { + useJUnitPlatform() +} diff --git a/dummy/Router/src/main/java/dummy/contract/router/Router.java b/dummy/Router/src/main/java/dummy/contract/router/Router.java new file mode 100644 index 00000000..a8bcd4f7 --- /dev/null +++ b/dummy/Router/src/main/java/dummy/contract/router/Router.java @@ -0,0 +1,46 @@ +package dummy.contract.router; + +import score.Address; +import score.Context; +import score.annotation.External; +import score.annotation.Optional; +import score.annotation.Payable; + +import java.math.BigInteger; +import community.icon.cps.score.lib.interfaces.RouterInterface; + +public class Router implements RouterInterface { + private static final String TAG = "Router"; + + public Router(){} + private void route(Address from, Address startToken, Address[] _path, BigInteger _minReceive) { + Address currentToken = _path[1]; + + + BigInteger balance = (BigInteger) Context.call(currentToken, "balanceOf", Context.getAddress()); + Context.require(balance.compareTo(_minReceive) >= 0, + TAG + ": Below minimum receive amount of " + _minReceive); + Context.call(currentToken, "transfer", from, _minReceive); + + } + + @Override + @Payable + @External + public void route(Address[] _path, @Optional BigInteger _minReceive) { + if (_minReceive == null) { + _minReceive = BigInteger.ZERO; + } + + Context.require(_minReceive.signum() >= 0, TAG + ": Must specify a positive number for minimum to receive"); + + Context.require(_path.length <= 2, + TAG + ": Passed max swaps of " + 2); + + route(Context.getCaller(), null, _path, Context.getValue()); + } + + @External + public void tokenFallback(Address _from, BigInteger _value, byte[] _data){ + } +} diff --git a/dummy/bnUSD/build.gradle b/dummy/bnUSD/build.gradle new file mode 100644 index 00000000..f752b4aa --- /dev/null +++ b/dummy/bnUSD/build.gradle @@ -0,0 +1,43 @@ +version = '0.9.1' + +dependencies { + compileOnly 'foundation.icon:javaee-api:0.9.2' + implementation 'com.github.sink772:javaee-tokens:0.6.1' + implementation project(':score-lib') + testImplementation 'foundation.icon:javaee-unittest:0.9.4' + testImplementation 'org.mockito:mockito-core:4.6.1' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' +} + +optimizedJar { + mainClassName = 'dummy.contract.bnusd.bnUSD' + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +deployJar { + endpoints { + lisbon { + uri = 'https://lisbon.net.solidwallet.io/api/v3' + nid = 0x2 + } + local { + uri = 'http://localhost:9082/api/v3' + nid = 0x3 + } + } + keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' + password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' + parameters { + arg('_name', 'Balanced Dollar') + arg('_symbol', 'bnUSD') + arg('_decimals', '0x12') + arg('_initialSupply', '0x989680') + } +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/dummy/bnUSD/src/main/java/dummy/contract/bnusd/bnUSD.java b/dummy/bnUSD/src/main/java/dummy/contract/bnusd/bnUSD.java new file mode 100644 index 00000000..0c1560d2 --- /dev/null +++ b/dummy/bnUSD/src/main/java/dummy/contract/bnusd/bnUSD.java @@ -0,0 +1,28 @@ +package dummy.contract.bnusd; + +import community.icon.cps.score.lib.interfaces.bnUSDInterface; +import community.icon.cps.score.lib.tokens.IRC2Base; +import score.Context; + +import java.math.BigInteger; + +public class bnUSD extends IRC2Base implements bnUSDInterface { + public bnUSD(String _name, String _symbol, int _decimals, BigInteger _initialSupply) { + super(_name, _symbol, BigInteger.valueOf(_decimals)); + + // mint the initial token supply here + Context.require(_initialSupply.compareTo(BigInteger.ZERO) >= 0); + mint(Context.getCaller(), _initialSupply.multiply(pow10(_decimals))); + } + + private static BigInteger pow10(int exponent) { + BigInteger result = BigInteger.ONE; + for (int i = 0; i < exponent; i++) { + result = result.multiply(BigInteger.TEN); + } + return result; + } + + +} + diff --git a/dummy/sICX/build.gradle b/dummy/sICX/build.gradle new file mode 100644 index 00000000..4f993073 --- /dev/null +++ b/dummy/sICX/build.gradle @@ -0,0 +1,43 @@ +version = '0.9.1' + +dependencies { + compileOnly 'foundation.icon:javaee-api:0.9.2' + implementation 'com.github.sink772:javaee-tokens:0.6.1' + implementation project(':score-lib') + testImplementation 'foundation.icon:javaee-unittest:0.9.4' + testImplementation 'org.mockito:mockito-core:4.6.1' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' +} + +optimizedJar { + mainClassName = 'dummy.contract.sicx.sICX' + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +deployJar { + endpoints { + lisbon { + uri = 'https://lisbon.net.solidwallet.io/api/v3' + nid = 0x2 + } + local { + uri = 'http://localhost:9082/api/v3' + nid = 0x3 + } + } + keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' + password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' + parameters { + arg('_name', 'Staked ICX') + arg('_symbol', 'sICX') + arg('_decimals', '0x12') + arg('_initialSupply', '0x989680') + } +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/dummy/sICX/src/main/java/dummy/contract/sicx/sICX.java b/dummy/sICX/src/main/java/dummy/contract/sicx/sICX.java new file mode 100644 index 00000000..993e5c54 --- /dev/null +++ b/dummy/sICX/src/main/java/dummy/contract/sicx/sICX.java @@ -0,0 +1,26 @@ +package dummy.contract.sicx; + +import com.iconloop.score.token.irc2.IRC2Basic; +import community.icon.cps.score.lib.tokens.IRC2Base; +import score.Context; + +import java.math.BigInteger; + +public class sICX extends IRC2Base implements community.icon.cps.score.lib.interfaces.sICXInterface { + public sICX(String _name, String _symbol, int _decimals, BigInteger _initialSupply) { + super(_name, _symbol, BigInteger.valueOf(_decimals)); + + // mint the initial token supply here + Context.require(_initialSupply.compareTo(BigInteger.ZERO) >= 0); + mint(Context.getCaller(), _initialSupply.multiply(pow10(_decimals))); + } + + private static BigInteger pow10(int exponent) { + BigInteger result = BigInteger.ONE; + for (int i = 0; i < exponent; i++) { + result = result.multiply(BigInteger.TEN); + } + return result; + } +} + From 8c28f1dee6ee0ff1edfd7d17195556755bfebc1c Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Thu, 17 Nov 2022 19:08:56 +0545 Subject: [PATCH 067/112] changed the version of dependencies and added mainnet url in deploy jar --- CPSCore/build.gradle | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle index e4579daf..4b10df2f 100644 --- a/CPSCore/build.gradle +++ b/CPSCore/build.gradle @@ -1,25 +1,21 @@ version = '0.9.1' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.1' + compileOnly 'foundation.icon:javaee-api:0.9.2' implementation 'com.github.sink772:minimal-json:0.9.7' - implementation 'foundation.icon:javaee-scorex:0.5.2' + implementation 'foundation.icon:javaee-scorex:0.5.3' implementation project(':score-lib') testImplementation project(':test-lib') - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation('org.mockito:mockito-inline:4.5.1') - testImplementation 'foundation.icon:javaee-unittest:0.9.4' - intTestImplementation "foundation.icon:icon-sdk:2.1.0" + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + testImplementation('org.mockito:mockito-inline:4.8.0') + testImplementation 'foundation.icon:javaee-unittest:0.9.7' + intTestImplementation 'foundation.icon:icon-sdk:2.2.0' intTestImplementation project(":score-client") intTestAnnotationProcessor project(":score-client") - - - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - - + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' } optimizedJar { @@ -34,21 +30,22 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 + to = "cxf10d8fb3e01142a6e89049c52dd0b0b7b28d3937" } local { uri = 'http://localhost:9082/api/v3' nid = 0x3 } - sejong { - uri = 'https://sejong.net.solidwallet.io/api/v3' - nid = 0x53 - - } berlin { uri = 'https://berlin.net.solidwallet.io/api/v3' nid = 0x7 - to = 'cx9c7017aca210ed21c5d043641ab3e30d1336a19e' } + mainnet { + uri = 'https://ctz.solidwallet.io/api/v3' + nid = 0x1 + to = 'cx9f4ab72f854d3ccdc59aa6f2c3e2215dd62e879f' + } + } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' @@ -59,3 +56,7 @@ deployJar { test { useJUnitPlatform() } + +repositories { + mavenCentral() +} From d689f17acc599cfcb7aeaa3080edf749db6df06b Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Thu, 17 Nov 2022 19:09:50 +0545 Subject: [PATCH 068/112] removed unused methods and variables --- .../icon/cps/score/cpscore/CPSCore.java | 54 ++++++------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 1e093254..00250f0a 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -33,8 +33,6 @@ public class CPSCore implements CPSCoreInterface { private final ArrayDB budgetApprovalsList = Context.newArrayDB(BUDGET_APPROVALS_LIST, String.class); private final ArrayDB activeProposals = Context.newArrayDB(ACTIVE_PROPOSALS, String.class); - private final ArrayDB votingProposals = Context.newArrayDB(VOTING_PROPOSALS, String.class); - private final ArrayDB votingProgressReports = Context.newArrayDB(VOTING_PROGRESS_REPORTS, String.class); private final ArrayDB
contributors = Context.newArrayDB(CONTRIBUTORS, Address.class); private final ArrayDB
sponsors = Context.newArrayDB(SPONSORS, Address.class); @@ -197,13 +195,6 @@ public boolean isAdmin(Address address) { return ArrayDBUtils.containsInArrayDb(address, admins); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public boolean is_admin(Address _address) { - return isAdmin(_address); - } - @Override @External public void toggleBudgetAdjustmentFeature() { @@ -225,12 +216,6 @@ public void toggleMaintenance() { setterGetter.maintenance.set(!setterGetter.maintenance.getOrDefault(Boolean.TRUE)); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void toggle_maintenance() { - toggleMaintenance(); - } @Override @External(readonly = true) @@ -242,14 +227,14 @@ public boolean getMaintenanceMode() { @Override @Payable public void fallback() { - Context.revert("ICX can only be sent while submitting a proposal or paying the penalty."); + Context.revert(TAG + ": ICX can only be sent while submitting a proposal or paying the penalty."); } private void burn(BigInteger amount, @Optional Address token) { - SetterGetter setterGetter = new SetterGetter(); if (token == null) { token = SYSTEM_ADDRESS; } + SetterGetter setterGetter = new SetterGetter(); if (token.equals(SYSTEM_ADDRESS)) { callScore(amount, SYSTEM_ADDRESS, "burn"); } else { @@ -281,12 +266,6 @@ public void addAdmin(Address address) { } } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void add_admin(Address _address) { - addAdmin(_address); - } @External public void removeAdmin(Address address) { // change made @@ -297,12 +276,6 @@ public void removeAdmin(Address address) { // change made ArrayDBUtils.removeArrayItem(admins, address); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void remove_admin(Address _address) { // change made - removeAdmin(_address); - } @External public void unregisterPrep() { @@ -331,6 +304,7 @@ public void unregister_prep() { @External public void registerPrep() { +// todo: check PRep list for candidate PRep after snapshot checkMaintenance(); update_period(); Address caller = Context.getCaller(); @@ -746,6 +720,7 @@ public void submitProposal(ProposalAttributes proposals) { PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(APPLICATION_PERIOD), TAG + ": Proposals can only be submitted on Application Period "); + Context.require(proposalsKeyListIndex.getOrDefault(proposals.ipfs_hash, 0) != 0, TAG + ": Proposal key already exists."); Context.require(!Context.getCaller().isContract(), TAG + ": Contract Address not supported."); Context.require(proposals.project_duration <= MAX_PROJECT_PERIOD, TAG + ": Maximum Project Duration exceeds " + MAX_PROJECT_PERIOD + " months."); @@ -765,7 +740,6 @@ public void submitProposal(ProposalAttributes proposals) { String ipfsHash = proposals.ipfs_hash; String ipfsHashPrefix = proposalPrefix(ipfsHash); -// TODO Check if prefix is already added or not addDataToProposalDB(proposals, ipfsHashPrefix); proposalsKeyList.add(proposals.ipfs_hash); proposalsKeyListIndex.set(ipfsHash, proposalsKeyList.size() - 1); @@ -919,8 +893,10 @@ public void submitProgressReport(ProgressReportAttributes progressReport) { Context.require(!progressSubmitted, TAG + ": Progress Report is already submitted this cycle."); String reportHash = progressReport.report_hash; + String ipfsHash = progressReport.ipfs_hash; Context.require(!_progress_key_exists(reportHash), TAG + ": Report key already exists."); - addNewProgressReportKey(progressReport.ipfs_hash, reportHash); + Context.require(proposalKeyExists(ipfsHash)); + addNewProgressReportKey(ipfsHash, reportHash); String reportHashPrefix = progressReportPrefix(reportHash); addDataToProgressReportDB(progressReport, reportHashPrefix); int percentageCompleted = progressReport.percentage_completed; @@ -1728,16 +1704,9 @@ private Map getProgressReportDetails(String progressKey) { for (int i = startIndex; i < endIndex; i++) { String progressReportKey = progressReportKeys.get(i); Map progressReportDetails = this.getProgressReportDetails(progressReportKey); - String ipfsKey = (String) progressReportDetails.get(IPFS_HASH); String progressStatus = (String) progressReportDetails.get(STATUS); if (progressStatus.equals(status)) { - Map proposalDetails = getProposalDetails(ipfsKey); - String projectTitle = (String) proposalDetails.get(PROJECT_TITLE); - String contributorAddress = proposalDetails.get(CONTRIBUTOR_ADDRESS).toString(); -// TODO: add them to hash map -// progressReportDetails.put(PROJECT_TITLE, projectTitle); -// progressReportDetails.put(CONTRIBUTOR_ADDRESS, contributorAddress); progressReportList.add(progressReportDetails); } } @@ -2538,4 +2507,13 @@ private void logger(String msg){ // ); // } + @External(readonly = true) + public BigInteger dummy(){ + BigInteger hello = BigInteger.ONE.negate(); + + hello = BigInteger.ZERO; + return hello; + + } + } \ No newline at end of file From 697ab69a8536889215f3094b8c055cd8f9d13b3b Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Thu, 17 Nov 2022 19:10:44 +0545 Subject: [PATCH 069/112] made variables private --- .../community/icon/cps/score/cpscore/db/ProposalDataDb.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java index 016387d9..f1afa1aa 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java @@ -11,8 +11,8 @@ import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; public class ProposalDataDb { - private static final BranchDB> ipfsHash = Context.newBranchDB(IPFS_HASH, String.class); - private static final BranchDB> projectTitle = Context.newBranchDB(PROJECT_TITLE, String.class); + public static final BranchDB> ipfsHash = Context.newBranchDB(IPFS_HASH, String.class); + public static final BranchDB> projectTitle = Context.newBranchDB(PROJECT_TITLE, String.class); public static final BranchDB> timestamp = Context.newBranchDB(TIMESTAMP, BigInteger.class); public static final BranchDB> totalBudget = Context.newBranchDB(TOTAL_BUDGET, BigInteger.class); public static final BranchDB> projectDuration = Context.newBranchDB(PROJECT_DURATION, Integer.class); From a711265dbbedc525a2dedda2101f4e6e6a7399a7 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Thu, 17 Nov 2022 19:11:24 +0545 Subject: [PATCH 070/112] added proposal title and contributors address in progress report details --- .../cpscore/db/ProgressReportDataDb.java | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java index f17eb552..27d0bc4b 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java @@ -62,30 +62,37 @@ public static void addDataToProgressReportDB(ProgressReportAttributes progressDa } public static Map getDataFromProgressReportDB(String prefix) { + String proposalHash = ipfsHash.at(prefix).getOrDefault(""); Map entryMap = - Map.ofEntries(Map.entry(IPFS_HASH, ipfsHash.at(prefix).getOrDefault("")), - Map.entry(REPORT_HASH, reportHash.at(prefix).getOrDefault("")), - Map.entry(PROGRESS_REPORT_TITLE, progressReportTitle.at(prefix).getOrDefault("")), - Map.entry(TIMESTAMP, timestamp.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(ADDITIONAL_BUDGET, additionalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(ADDITIONAL_DURATION, additionalMonth.at(prefix).getOrDefault(0)), - Map.entry(STATUS, status.at(prefix).getOrDefault("")), - Map.entry(TX_HASH, txHash.at(prefix).getOrDefault("")), - Map.entry(TOTAL_VOTES, totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(APPROVED_VOTES, approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(REJECTED_VOTES, rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(TOTAL_VOTERS, totalVoters.at(prefix).getOrDefault(0)), - Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), - Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size()), - Map.entry(BUDGET_APPROVED_VOTES, budgetApprovedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(BUDGET_REJECTED_VOTES, budgetRejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(BUDGET_APPROVE_VOTERS, budgetApproveVoters.at(prefix).size()), - Map.entry(BUDGET_REJECT_VOTERS, budgetRejectVoters.at(prefix).size()), - Map.entry(BUDGET_ADJUSTMENT_STATUS, budgetAdjustmentStatus.at(prefix).getOrDefault("")), - Map.entry(IPFS_LINK, ipfsLink.at(prefix).getOrDefault("")), - Map.entry(PERCENTAGE_COMPLETED, percentageCompleted.at(prefix).getOrDefault(0)), - Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false))); + Map.ofEntries(Map.entry(IPFS_HASH, proposalHash), + Map.entry(REPORT_HASH, reportHash.at(prefix).getOrDefault("")), + Map.entry(PROGRESS_REPORT_TITLE, progressReportTitle.at(prefix).getOrDefault("")), + Map.entry(TIMESTAMP, timestamp.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(ADDITIONAL_BUDGET, additionalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(ADDITIONAL_DURATION, additionalMonth.at(prefix).getOrDefault(0)), + Map.entry(STATUS, status.at(prefix).getOrDefault("")), + Map.entry(TX_HASH, txHash.at(prefix).getOrDefault("")), + Map.entry(TOTAL_VOTES, totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(APPROVED_VOTES, approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(REJECTED_VOTES, rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(TOTAL_VOTERS, totalVoters.at(prefix).getOrDefault(0)), + Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), + Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size()), + Map.entry(BUDGET_APPROVED_VOTES, budgetApprovedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(BUDGET_REJECTED_VOTES, budgetRejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(BUDGET_APPROVE_VOTERS, budgetApproveVoters.at(prefix).size()), + Map.entry(BUDGET_REJECT_VOTERS, budgetRejectVoters.at(prefix).size()), + Map.entry(BUDGET_ADJUSTMENT_STATUS, budgetAdjustmentStatus.at(prefix).getOrDefault("")), + Map.entry(IPFS_LINK, ipfsLink.at(prefix).getOrDefault("")), + Map.entry(PERCENTAGE_COMPLETED, percentageCompleted.at(prefix).getOrDefault(0)), + Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false)), + Map.entry(PROJECT_TITLE, ProposalDataDb.projectTitle.at(proposalPrefix(proposalHash)).getOrDefault("")), + Map.entry(CONTRIBUTOR_ADDRESS, ProposalDataDb.contributorAddress.at(proposalPrefix(proposalHash)).get())); + return entryMap; } -} + public static String proposalPrefix(String proposalKey) { + return PROPOSAL_DB_PREFIX + "|" + "|" + proposalKey; + } +} \ No newline at end of file From 3cb67e9b66664a0508753a75b95b919e99e6da48 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Thu, 17 Nov 2022 19:12:05 +0545 Subject: [PATCH 071/112] refactored CPSCoreInterface methods --- .../icon/cps/score/lib/interfaces/CPSCoreInterface.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java index 43f9415b..a2b10d21 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java @@ -82,7 +82,7 @@ public static class ProgressReportAttributes { @External(readonly = true) - boolean is_admin(Address _address); + boolean isAdmin(Address address); @External void toggleBudgetAdjustmentFeature(); @@ -92,7 +92,7 @@ public static class ProgressReportAttributes { @External - void toggle_maintenance(); + void toggleMaintenance(); @External(readonly = true) boolean getMaintenanceMode(); @@ -102,11 +102,11 @@ public static class ProgressReportAttributes { @External - void add_admin(Address _address); + void addAdmin(Address address); @External - void remove_admin(Address _address); + void removeAdmin(Address address); @External From 3a3175b99f27c8d3619eb57ae4d4a6e23a35f3e9 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 14:47:40 +0545 Subject: [PATCH 072/112] added lisbon testnet contract addresses in deploy jar --- CPFTreasury/build.gradle | 2 ++ CPSCore/build.gradle | 2 +- CPSTreasury/build.gradle | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CPFTreasury/build.gradle b/CPFTreasury/build.gradle index f3ae9c14..c3acc381 100644 --- a/CPFTreasury/build.gradle +++ b/CPFTreasury/build.gradle @@ -28,6 +28,7 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 + to = 'cx3d4182c0e783b7ef97ba63409c4bdf808853bd9f' } local { uri = 'http://localhost:9082/api/v3' @@ -47,6 +48,7 @@ deployJar { keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' parameters { + arg('score', 'cx0355e153f269c05f64100d34d3c48a002b404dc5') } } diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle index 4b10df2f..971a1788 100644 --- a/CPSCore/build.gradle +++ b/CPSCore/build.gradle @@ -30,7 +30,7 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 - to = "cxf10d8fb3e01142a6e89049c52dd0b0b7b28d3937" + to = 'cx0355e153f269c05f64100d34d3c48a002b404dc5' } local { uri = 'http://localhost:9082/api/v3' diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index 48c3694e..865069bd 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -28,6 +28,7 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 + to = 'cxda945837404c889bf001546cc6705bd6ac40f077' } local { uri = 'http://localhost:9082/api/v3' @@ -45,7 +46,9 @@ deployJar { } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' - parameters {} + parameters { + arg('score', 'cx0355e153f269c05f64100d34d3c48a002b404dc5') + } } test { From 25b34c45eef7c1007098874caed73d0e4b8b69ba Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 14:49:05 +0545 Subject: [PATCH 073/112] changed the method add_admin to addAdmin --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 5c5e8356..01811924 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -95,7 +95,7 @@ private Boolean proposalExists(String _ipfs_key) { } private void validateAdmins() { - Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "is_admin", Context.getCaller()); + Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "isAdmin", Context.getCaller()); Context.require(isAdmin, TAG + ": Only admins can call this method"); } From 509ef864ba691aecfac759f7fa984dd4ebc6d9a1 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 14:49:37 +0545 Subject: [PATCH 074/112] changed the method name from add_admin to addAdmin --- .../java/community/icon/cps/score/cpftreasury/Validations.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java index 967dbc33..77d39709 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java @@ -7,7 +7,7 @@ public class Validations { public static void validateAdmins() { - Context.require((Boolean) Context.call(CPFTreasury.cpsScore.get(), "is_admin", Context.getCaller()), + Context.require((Boolean) Context.call(CPFTreasury.cpsScore.get(), "isAdmin", Context.getCaller()), TAG + ": Only Admins can call this method"); } From 6d11581d577ee053c2069dfcca3b394992f5fcf7 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 14:51:33 +0545 Subject: [PATCH 075/112] fixed voting prep issue by using getPRep method from the SYSTEM SCORE --- .../icon/cps/score/cpscore/CPSCore.java | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 00250f0a..821b9989 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -343,6 +343,10 @@ private List> getPrepTerm() { return (List>) prepDict.get("preps"); } + private Map getPRepInfo(Address address){ + return callScore(Map.class, SYSTEM_ADDRESS, "getPRep", address); + } + private List
getPrepsAddress() { List
prepsList = new ArrayList<>(); @@ -354,23 +358,11 @@ private List
getPrepsAddress() { } private String getPrepName(Address address) { - for (Map preps : getPrepTerm()) { - Address prepAddress = (Address) preps.get("address"); - if (prepAddress.equals(address)) { - return (String) preps.get("name"); - } - } - return ""; + return (String) getPRepInfo(address).get("name"); } private BigInteger getStake(Address address) { - for (Map preps : getPrepTerm()) { - Address prepAddress = (Address) preps.get("address"); - if (prepAddress.equals(address)) { - return (BigInteger) preps.get("power"); - } - } - return BigInteger.ZERO; + return (BigInteger) getPRepInfo(address).get("power"); } private void setPreps() { @@ -720,7 +712,7 @@ public void submitProposal(ProposalAttributes proposals) { PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(APPLICATION_PERIOD), TAG + ": Proposals can only be submitted on Application Period "); - Context.require(proposalsKeyListIndex.getOrDefault(proposals.ipfs_hash, 0) != 0, TAG + ": Proposal key already exists."); + Context.require(proposalsKeyListIndex.getOrDefault(proposals.ipfs_hash, 0) == 0, TAG + ": Proposal key already exists."); Context.require(!Context.getCaller().isContract(), TAG + ": Contract Address not supported."); Context.require(proposals.project_duration <= MAX_PROJECT_PERIOD, TAG + ": Maximum Project Duration exceeds " + MAX_PROJECT_PERIOD + " months."); @@ -2328,7 +2320,7 @@ public List> get_active_proposals() { /*** Returns a dict of proposals of provided status :param walletAddress : user Signing in - :type walletAddress : 'iconservice.base.address' + :type walletAddress : "iconservice.base.address" :return: List of all proposals_details ***/ @External(readonly =true) @@ -2452,17 +2444,14 @@ private void logger(String msg){ /****************************************************************************************************************** To be removed in production ****************************************************************************************************************/ - +// // @External // public void register_prep_(Address caller) { // validateAdmins(); // checkMaintenance(); // update_period(); -// List
prepList = getPrepsAddress(); // PReps pReps = new PReps(); // -// Context.require(prepList.contains(caller), -// TAG + ": Not a P-Rep."); // Context.require(!ArrayDBUtils.containsInArrayDb(caller, pReps.registeredPreps), // TAG + ": P-Rep is already registered."); // Context.require(!ArrayDBUtils.containsInArrayDb(caller, pReps.denylist), @@ -2507,13 +2496,30 @@ private void logger(String msg){ // ); // } - @External(readonly = true) - public BigInteger dummy(){ - BigInteger hello = BigInteger.ONE.negate(); +// @External(readonly = true) +// public BigInteger dummy(){ +// BigInteger hello = BigInteger.ONE.negate(); +// +// hello = BigInteger.ZERO; +// return hello; +// } + +// @External(readonly = true) +// public Map getPrepInfo(Address address){ +// return getPRepInfo(address); +// } +// +// @External(readonly = true) +// public String getName(Address address){ +// return getPrepName(address); +// } +// +// @External(readonly = true) +// public BigInteger stake(Address address){ +// return getStake(address); +// } + - hello = BigInteger.ZERO; - return hello; - } } \ No newline at end of file From a370125a0b63d33799ebceda0a66a3909d25e6a2 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 21:51:57 +0545 Subject: [PATCH 076/112] removed commented codes from CPSCore contract --- .../icon/cps/score/cpscore/CPSCore.java | 179 ++++-------------- 1 file changed, 37 insertions(+), 142 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 821b9989..0d26f81d 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -519,7 +519,7 @@ public void set_initialBlock() { } @External(readonly = true) - public Map loginPrep(Address address) { // added for is prep but not registered + public Map loginPrep(Address address) { Map loginData = new HashMap<>(); List
allPreps = getPrepsAddress(); PReps pReps = new PReps(); @@ -537,7 +537,6 @@ else if (ArrayDBUtils.containsInArrayDb(address, pReps.denylist)) { loginData.put("votingPRep", BigInteger.ZERO); loginData.put("penaltyAmount", getPenaltyAmount(address)); } -// If a P-Rep registers on Voting period, P-Rep status will be registered. else if (ArrayDBUtils.containsInArrayDb(address, pReps.registeredPreps)) { loginData.put("isRegistered", BigInteger.ONE); loginData.put("payPenalty", BigInteger.ZERO); @@ -642,7 +641,7 @@ public List
get_denylist() { } @External(readonly = true) - public Map getPeriodStatus() { // added getOrDefault in next block + public Map getPeriodStatus() { PeriodController period = new PeriodController(); BigInteger remainingTime = period.nextBlock.getOrDefault(BigInteger.ZERO).subtract(BigInteger.valueOf(Context.getBlockHeight())).multiply(BigInteger.valueOf(2)); if (remainingTime.compareTo(BigInteger.ZERO) < 0) { @@ -1192,7 +1191,7 @@ public Map get_sponsors_record() { } @External - public void updatePeriod() { // changed the checking + public void updatePeriod() { checkMaintenance(); BigInteger currentBlock = BigInteger.valueOf(Context.getBlockHeight()); PeriodController period = new PeriodController(); @@ -1275,7 +1274,6 @@ private void updateDenylistPreps() { PRepPenalty(prep, "P-Rep added to Denylist."); } -//Clear all data from the ArrayDB ArrayDBUtils.clearArrayDb(pReps.inactivePreps); } @@ -1563,24 +1561,6 @@ private void updateProgressReportStatus(String progressHash, String progressStat } private void checkInactivePreps(ArrayDB
prepList) { -// Map voters = new HashMap<>(); -// for (int i = 0; i < prepList.size(); i++) { -// Address prep = (Address) prepList.get(i); -// voters.put(prep, 0); -// } -// PReps pReps = new PReps(); -// List
notVoters = new ArrayList<>(); -// for (int i = 0; i < pReps.validPreps.size(); i++) { -// Address prep = pReps.validPreps.get(i); -// if (voters.containsKey(prep)) { -// notVoters.add(prep); -// } -// } -// for (Address prep : notVoters) { -// if (!ArrayDBUtils.containsInArrayDb(prep, pReps.inactivePreps)) { -// pReps.inactivePreps.add(prep); -// } -// } PReps pReps = new PReps(); for(int i = 0; i < pReps.validPreps.size(); i++){ Address prep = pReps.validPreps.get(i); @@ -1837,42 +1817,40 @@ public Map get_sponsors_requests(String _status, Address _sponso :type _wallet_address: str :return: list of details of proposal or progress report what they need to vote on the same voting period ***/ -// @External(readonly = true) -// public List> get_remaining_project(String _project_type, Address _wallet_address) { -// -// List> _remaining_proposals = new ArrayList<>(); -// List> _remaining_progress_report = new ArrayList<>(); -// if (_project_type.equals(PROPOSAL)) { -// List _proposal_keys = get_proposals_keys_by_status(PENDING); -// -// for (String _ipfs_key: _proposal_keys) { -// String prefix = proposalPrefix(_ipfs_key); -// -// if (!containsInArrayDb(_wallet_address, ProposalDataDb.votersList.at(prefix))){ -// Map _proposal_details = getProposalDetails(_ipfs_key); -// _remaining_proposals.add(_proposal_details); -// } -// } -// return _remaining_proposals; -// } -// -// if (_project_type.equals(PROGRESS_REPORTS)) { -// for (int i = 0; i < waitingProgressReports.size(); i++) { -// prefix = self.progress_report_prefix(_report_key) -// _voters_list = self.progress_reports[prefix].voters_list -// -// if (!containsInArrayDb(_wallet_address, ProgressReportDataDb.votersList.at(pre))) -// _progress_reports_details = self._get_progress_reports_details(_report_key) -// _ipfs_hash = _progress_reports_details.get(IPFS_HASH) -// _progress_reports_details[PROJECT_TITLE] = self._get_proposal_details(_ipfs_hash). -// -// get(PROJECT_TITLE) -// _remaining_progress_report.append(_progress_reports_details) -// } -// -// return _remaining_progress_report -// } -//} + @External(readonly = true) + public List> get_remaining_project(String _project_type, Address _wallet_address) { + List> _remaining_proposals = new ArrayList<>(); + List> _remaining_progress_report = new ArrayList<>(); + if (_project_type.equals(PROPOSAL)) { + List _proposal_keys = get_proposals_keys_by_status(PENDING); + + for (String _ipfs_key : _proposal_keys) { + String prefix = proposalPrefix(_ipfs_key); + + if (!containsInArrayDb(_wallet_address, ProposalDataDb.votersList.at(prefix))) { + Map _proposal_details = getProposalDetails(_ipfs_key); + _remaining_proposals.add(_proposal_details); + } + } + return _remaining_proposals; + } + + if (_project_type.equals(PROGRESS_REPORTS)) { + for (int i = 0; i < waitingProgressReports.size(); i++) { + String reportHash = waitingProgressReports.get(i); + String prefix = progressReportPrefix(reportHash); + + if (!containsInArrayDb(_wallet_address, ProgressReportDataDb.votersList.at(prefix))) { + Map progressReportDetails = getProgressReportDetails(reportHash); + _remaining_progress_report.add(progressReportDetails); + } + } + + return _remaining_progress_report; + } + return List.of(Map.of("", "")); + } + /*** Get vote results by proposal @@ -2439,87 +2417,4 @@ public void callScore(BigInteger amount, Address address, String method, Object. private void logger(String msg){ Context.println(msg); } - - - /****************************************************************************************************************** - To be removed in production - ****************************************************************************************************************/ -// -// @External -// public void register_prep_(Address caller) { -// validateAdmins(); -// checkMaintenance(); -// update_period(); -// PReps pReps = new PReps(); -// -// Context.require(!ArrayDBUtils.containsInArrayDb(caller, pReps.registeredPreps), -// TAG + ": P-Rep is already registered."); -// Context.require(!ArrayDBUtils.containsInArrayDb(caller, pReps.denylist), -// TAG + ": You are in denylist. To register, You've to pay Penalty."); -// -// if (ArrayDBUtils.containsInArrayDb(caller, pReps.unregisteredPreps)) { -// ArrayDBUtils.removeArrayItem(pReps.unregisteredPreps, caller); -// } -// pReps.registeredPreps.add(caller); -// RegisterPRep(caller, "P-Rep Registered."); -// PeriodController period = new PeriodController(); -// pReps.validPreps.add(caller); -// -// } -// -// @External -// public void payPrepPenalty_(Address from, BigInteger _value) { -// validateAdmins(); -// checkMaintenance(); -// update_period(); -// PReps pReps = new PReps(); -// Context.require(ArrayDBUtils.containsInArrayDb(from, pReps.denylist), -// TAG + " " + from + " not in denylist."); -// ArrayDBUtils.removeArrayItem(pReps.denylist, from); -// pReps.registeredPreps.add(from); -// pReps.validPreps.add(from); -// PRepPenalty(from, _value + " bnUSD Penalty Received. P-Rep removed from Denylist."); -// -// } -// -// @External -// public void setProposalFees(BigInteger value){ -// validateAdmins(); -// proposalFees.set(value); -// } -// -// @External(readonly = true) -// public Map getProposalFees(){ -// return Map.of( -// "proposalFees", proposalFees.get(), -// "cpsBalance", Context.getBalance(Context.getAddress()) -// ); -// } - -// @External(readonly = true) -// public BigInteger dummy(){ -// BigInteger hello = BigInteger.ONE.negate(); -// -// hello = BigInteger.ZERO; -// return hello; -// } - -// @External(readonly = true) -// public Map getPrepInfo(Address address){ -// return getPRepInfo(address); -// } -// -// @External(readonly = true) -// public String getName(Address address){ -// return getPrepName(address); -// } -// -// @External(readonly = true) -// public BigInteger stake(Address address){ -// return getStake(address); -// } - - - - } \ No newline at end of file From 222976de3f9191e47d8563a15441c2751f0e0a27 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 22:04:41 +0545 Subject: [PATCH 077/112] fixed admin check issue in CPF Treasury contract --- .../cps/score/cpftreasury/CPFTreasury.java | 2 +- .../score/cpftreasury/CPFTTreasuryTest.java | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java index b24ffb31..9d7d8f63 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java @@ -283,7 +283,7 @@ public void reset_swap_state() { Address cpsScoreAddress = cpsScore.get(); Address caller = Context.getCaller(); - boolean checkCaller = caller.equals(cpsScoreAddress) || (Boolean) Context.call(cpsScoreAddress, "is_admin", caller); + boolean checkCaller = caller.equals(cpsScoreAddress) || (Boolean) Context.call(cpsScoreAddress, "isAdmin", caller); Context.require(checkCaller, TAG + ": Only admin can call this method."); swapState.set(SwapContinue); swapCount.set(SwapReset); diff --git a/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java b/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java index 1dccddc2..5c6a3c06 100644 --- a/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java +++ b/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java @@ -85,7 +85,7 @@ public void setMaximumTreasuryFundBNUSDExceptions(Account address) { void setCPSScore() { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setCpsScore", score_address); } assertEquals(score_address, tokenScore.call("getCpsScore")); @@ -95,7 +95,7 @@ void setCPSScore() { void setCPSTreasuryScore() { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setCpsTreasuryScore", score_address); } assertEquals(score_address, tokenScore.call("getCpsTreasuryScore")); @@ -105,7 +105,7 @@ void setCPSTreasuryScore() { void setBMUSDScore() { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setBnUSDScore", score_address); } assertEquals(score_address, tokenScore.call("getBnUSDScore")); @@ -115,7 +115,7 @@ void setBMUSDScore() { void setSICXScore() { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setSicxScore", score_address); } assertEquals(score_address, tokenScore.call("getSicxScore")); @@ -125,7 +125,7 @@ void setSICXScore() { void setDEXScore() { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setDexScore", score_address); } assertEquals(score_address, tokenScore.call("getDexScore")); @@ -135,7 +135,7 @@ void setDEXScore() { void setRouterScore() { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setRouterScore", score_address); } assertEquals(score_address, tokenScore.call("getRouterScore")); @@ -184,7 +184,7 @@ void setDEXScoreExceptions(Account address, Address _score) { void setRouterScoreExceptions(Account address, Address _score) { VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(false); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(false); tokenScore.invoke(address, "setRouterScore", _score); } catch (Exception e) { throw e; @@ -294,7 +294,7 @@ void updateProposalFund() { void setMaxCapIcxAndBnusd(){ VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER)); tokenScore.invoke(owner, "setMaximumTreasuryFundBnusd", BigInteger.valueOf(2000).multiply(MULTIPLIER)); @@ -305,7 +305,7 @@ void setMaxCapIcxAndBnusd(){ void setMaxCapIcxAndBnusdTest(){ VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER)); tokenScore.invoke(owner, "setMaximumTreasuryFundBnusd", BigInteger.valueOf(2000).multiply(MULTIPLIER)); } @@ -389,7 +389,7 @@ void resetSwapState() { setCPSScoreMethod(score_address); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.getCaller()).thenReturn(testing_account.getAddress()); - theMock.when(() -> Context.call(score_address, "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(score_address, "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "reset_swap_state"); assertEquals(tokenScore.call("get_swap_state_status"), Map.of("state", 0, "count", 0)); } @@ -695,7 +695,7 @@ public void expectErrorMessage(Executable contractCall, String errorMessage) { void setCPSScoreMethod(Address scoreAddress) { VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setCpsScore", scoreAddress); } } @@ -703,7 +703,7 @@ void setCPSScoreMethod(Address scoreAddress) { void setCPSTreasuryScoreMetod(Address scoreAddress) { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setCpsTreasuryScore", scoreAddress); } } @@ -711,7 +711,7 @@ void setCPSTreasuryScoreMetod(Address scoreAddress) { void setBMUSDScoreMethod(Address scoreAddress) { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setBnUSDScore", scoreAddress); } } @@ -719,7 +719,7 @@ void setBMUSDScoreMethod(Address scoreAddress) { void setSICXScoreMethod(Address scoreAddress) { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setSicxScore", scoreAddress); } } @@ -727,7 +727,7 @@ void setSICXScoreMethod(Address scoreAddress) { void setDEXScoreMethod(Address scoreAddress) { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setDexScore", scoreAddress); } } @@ -735,7 +735,7 @@ void setDEXScoreMethod(Address scoreAddress) { void setRouterScoreMethod(Address scoreAddress) { VarDB
cpsScore = mock(VarDB.class); try(MockedStatic theMock = Mockito.mockStatic(Context.class)){ - theMock.when(() -> Context.call(cpsScore.get(), "is_admin", Context.getCaller())).thenReturn(true); + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setRouterScore", score_address); } } From 4edbec17deabc0026c2ffbe5614e10ef4314ffa1 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 22:24:33 +0545 Subject: [PATCH 078/112] fixed cpsCore failing unit tests --- .../icon/cps/score/cpscore/CPSScoreTest.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java index a403ab7c..99e6f4a4 100644 --- a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java +++ b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java @@ -106,7 +106,7 @@ void name(){ @Test void addAdmin(){ - cpsScore.invoke(owner, "add_admin", testingAccount.getAddress()); + cpsScore.invoke(owner, "addAdmin", testingAccount.getAddress()); assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("get_admins")); } @@ -118,9 +118,9 @@ void addAdminNotOwner(){ @Test void removeAdmin(){ - cpsScore.invoke(owner, "add_admin", testingAccount.getAddress()); + cpsScore.invoke(owner, "addAdmin", testingAccount.getAddress()); assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("getAdmins")); - cpsScore.invoke(owner, "remove_admin", testingAccount.getAddress()); + cpsScore.invoke(owner, "removeAdmin", testingAccount.getAddress()); assertEquals(0, ((List) cpsScore.call("getAdmins")).size()); } @@ -165,7 +165,8 @@ void registerPrepAlreadyRegistered(){ addAdminMethod(); doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); - cpsScore.invoke(owner, "toggle_maintenance"); + doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); + cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); cpsScore.invoke(owner, "register_prep"); Executable register = () -> cpsScore.invoke(owner, "register_prep"); @@ -187,6 +188,7 @@ void registerPrepNotAPrep(){ addAdminMethod(); doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); Executable register = () -> cpsScore.invoke(testingAccount6, "register_prep"); @@ -210,6 +212,7 @@ void registerPrepPrepInDenyList(){ addAdminMethod(); doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); // contextMock.when() @@ -232,6 +235,7 @@ void unregisterPrep(){ addAdminMethod(); doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); @@ -265,6 +269,7 @@ void unregisterPrepNotInValidPrep(){ addAdminMethod(); doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); cpsScore.invoke(owner, "register_prep"); @@ -288,6 +293,7 @@ void loginPrep(){ addAdminMethod(); doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); cpsScore.invoke(owner, "register_prep"); @@ -334,6 +340,7 @@ void getPeriodStatus(){ addAdminMethod(); doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); @@ -367,6 +374,7 @@ private void registerPrepsMethod(){ addAdminMethod(); doReturn(preps).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRepTerm")); + doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); cpsScore.invoke(owner, "register_prep"); @@ -1107,9 +1115,9 @@ void payPrepPenalty(){ JsonObject burnTokens = new JsonObject(); burnTokens.add("method", "burn_amount"); - doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(new BigInteger("1250000000000000000")), eq(burnTokens.toString().getBytes())); + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(new BigInteger("5000000000000000000")), eq(burnTokens.toString().getBytes())); contextMock.when(caller()).thenReturn(bnUSDScore); - cpsScore.invoke(owner, "tokenFallback", testingAccount5.getAddress(), new BigInteger("1250000000000000000"), payPenalty.toString().getBytes()); + cpsScore.invoke(owner, "tokenFallback", testingAccount5.getAddress(), new BigInteger("5000000000000000000"), payPenalty.toString().getBytes()); } @Test @@ -1331,7 +1339,7 @@ void setSwapCount(){ @Test void fallback(){ Executable fallback = () -> cpsScore.invoke(owner, "fallback"); - expectErrorMessage(fallback, "Reverted(0): " + "ICX can only be sent while submitting a proposal or paying the penalty."); + expectErrorMessage(fallback, "Reverted(0): " + TAG +": ICX can only be sent while submitting a proposal or paying the penalty."); } @Test From 4a85fc991ece8955cca0ccae09aa1d8eeb706c20 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 22:32:55 +0545 Subject: [PATCH 079/112] fixed CPS Treasury failing test issues --- .../icon/cps/score/cpstreasury/CPSTreasuryTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index 375b0981..b3f399bd 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -95,7 +95,7 @@ void setCpsScore() { } private void setCpsScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); assertEquals(score_address, tokenScore.call("getCpsScore")); } @@ -106,7 +106,7 @@ void setCPFTreasuryScore() { } private void setCPFTreasuryScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpfTreasuryScore", cpfTreasury); assertEquals(cpfTreasury, tokenScore.call("getCpfTreasuryScore")); } @@ -117,23 +117,23 @@ void setBnUSDScore() { } private void setBnUSDScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setBnUSDScore", bnUSDScore); assertEquals(bnUSDScore, tokenScore.call("getBnUSDScore")); } void setCpsScoreExceptions(Boolean isAdmin, Address score_address) { - doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); } void setCpfTreasuryScoreExceptions(Boolean isAdmin, Address score_address) { - doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpfTreasuryScore", score_address); } void setBnUSDScoreExceptions(Boolean isAdmin, Address score_address) { - doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setBnUSDScore", score_address); } From 3191f1ae4cb0f54f768210e321ccd0d8dbad60e0 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Fri, 18 Nov 2022 22:42:54 +0545 Subject: [PATCH 080/112] update deprecated method --- .../src/main/java/community/icon/cps/score/cpscore/CPSCore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 0d26f81d..b3eb3429 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -1421,7 +1421,7 @@ private void updateBudgetAdjustments(String _budget_key) { Map _report_result = getProgressReportDetails(_budget_key); String _prefix = progressReportPrefix(_budget_key); - Map _vote_result = get_budget_adjustment_vote_result(_budget_key); + Map _vote_result = getBudgetAdjustmentVoteResult(_budget_key); int _approve_voters = (int) _vote_result.get(APPROVE_VOTERS); int _total_voters = (int) _vote_result.get(TOTAL_VOTERS); BigInteger _approved_votes = (BigInteger) _vote_result.get(APPROVED_VOTES); From 6cae4222e80f692fc2ceaad32d5726e9a3fecdb1 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Fri, 18 Nov 2022 22:43:12 +0545 Subject: [PATCH 081/112] comment out github actions --- .github/workflows/pr-test.yml | 32 ++++++++++++++++---------------- .github/workflows/push-main.yml | 32 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml index 7f03e50f..341fd0e6 100644 --- a/.github/workflows/pr-test.yml +++ b/.github/workflows/pr-test.yml @@ -1,16 +1,16 @@ -name: pr-test - -on: - pull_request: - branches: - - '*' - -jobs: - docker: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Build optimized jar - run: ./gradlew clean build optimizedJar \ No newline at end of file +#name: pr-test +# +#on: +# pull_request: +# branches: +# - '*' +# +#jobs: +# docker: +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 +# +# - name: Build optimized jar +# run: ./gradlew clean build optimizedJar \ No newline at end of file diff --git a/.github/workflows/push-main.yml b/.github/workflows/push-main.yml index 1dc36eff..1a5bbab4 100644 --- a/.github/workflows/push-main.yml +++ b/.github/workflows/push-main.yml @@ -1,16 +1,16 @@ -name: push-main - -on: - push: - branches: - - main - -jobs: - docker: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Build optimized jar - run: ./gradlew clean build optimizedJar \ No newline at end of file +#name: push-main +# +#on: +# push: +# branches: +# - main +# +#jobs: +# docker: +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 +# +# - name: Build optimized jar +# run: ./gradlew clean build optimizedJar \ No newline at end of file From 4f3e12f639944a79fb436a69a190efdb2a900ec8 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 18 Nov 2022 22:57:40 +0545 Subject: [PATCH 082/112] added abstain vote migration feature --- .../icon/cps/score/cpscore/CPSCore.java | 17 ++++++++++------- .../icon/cps/score/cpscore/utils/Constants.java | 4 +++- .../icon/cps/score/cpscore/utils/Migration.java | 11 +++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Migration.java diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index b3eb3429..b7c13262 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -23,6 +23,7 @@ import static community.icon.cps.score.cpscore.utils.Checkers.*; import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; import community.icon.cps.score.lib.interfaces.CPSCoreInterface; +import community.icon.cps.score.cpscore.utils.Migration; public class CPSCore implements CPSCoreInterface { @@ -846,14 +847,16 @@ public void vote_proposal(String _ipfs_key, String _vote, String _vote_reason, @ } @External - public void migrateAbstainVotes(){ + public void migrateAbstainVotes(Migration[] migrations){ validateAdmins(); - PeriodController periodController = new PeriodController(); - Context.require(periodController.periodName.get().equals(APPLICATION_PERIOD)); - int size = proposalsKeyList.size(); - for(int i = 0; i < size; i++){ - String proposalPrefix = proposalPrefix(proposalsKeyList.get(i)); - abstainedVotes.at(proposalPrefix).set(BigInteger.ZERO); + Context.require(migrations.length <= MIGRATION_BATCH, TAG + ": The length of data should be " + + "smaller than or equal to " + MIGRATION_BATCH); + for (Migration migration : migrations) { + String proposalPrefix = proposalPrefix(migration.ipfsHash); + for (int j = 0; j < migration.abstainVoters.length; j++) { + abstainVoters.at(proposalPrefix).add(migration.abstainVoters[j]); + } + abstainedVotes.at(proposalPrefix).set(migration.abstainVotes); } } diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java index 1445c85f..eec154b0 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java @@ -186,4 +186,6 @@ public class Constants { public static final Integer PENALTY_LEVELS = 3; -} + // migration + public static final int MIGRATION_BATCH = 10; +} \ No newline at end of file diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Migration.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Migration.java new file mode 100644 index 00000000..61c28494 --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Migration.java @@ -0,0 +1,11 @@ +package community.icon.cps.score.cpscore.utils; + +import score.Address; + +import java.math.BigInteger; + +public class Migration { + public String ipfsHash; + public Address[] abstainVoters; + public BigInteger abstainVotes; +} \ No newline at end of file From cec3c4a816e593cc1bcd76c9889e3246d12b833b Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Sat, 19 Nov 2022 11:08:35 +0545 Subject: [PATCH 083/112] added is_admin method --- .../java/community/icon/cps/score/cpscore/CPSCore.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index b7c13262..378163f8 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -196,9 +196,16 @@ public boolean isAdmin(Address address) { return ArrayDBUtils.containsInArrayDb(address, admins); } + @Deprecated + @External + public boolean is_admin(Address _address) { + return isAdmin(_address); + } + @Override @External public void toggleBudgetAdjustmentFeature() { + validateAdmins(); SetterGetter setterGetter = new SetterGetter(); setterGetter.budgetAdjustment.set(!setterGetter.budgetAdjustment.getOrDefault(false)); } From f72bd7c08d869113e9509135bb8d62c0f892c976 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Sat, 19 Nov 2022 11:09:12 +0545 Subject: [PATCH 084/112] added sejong test net contract address --- CPSTreasury/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index 865069bd..1e0c4dfc 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -37,6 +37,7 @@ deployJar { sejong{ uri = 'https://sejong.net.solidwallet.io/api/v3' nid = 0x53 + to = 'cxb33f0187a22a41c3ecb05a9756af320e98badb7d' } berlin{ uri = 'https://berlin.net.solidwallet.io/api/v3' @@ -47,7 +48,6 @@ deployJar { keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' parameters { - arg('score', 'cx0355e153f269c05f64100d34d3c48a002b404dc5') } } From 0c6511ac12a8ace0b132d905310ecf3bc907dc37 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Sat, 19 Nov 2022 11:09:59 +0545 Subject: [PATCH 085/112] commented out integration tests --- .../score/cpstreasury/CPSTreasuryIntTest.java | 784 +++++++++--------- 1 file changed, 392 insertions(+), 392 deletions(-) diff --git a/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java b/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java index efe79e39..cc64d126 100644 --- a/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java +++ b/CPSTreasury/src/intTest/java/community/icon/cps/score/cpstreasury/CPSTreasuryIntTest.java @@ -1,393 +1,393 @@ -package community.icon.cps.score.cpstreasury; - -import com.eclipsesource.json.JsonObject; -import community.icon.cps.score.lib.interfaces.*; - -import community.icon.cps.score.test.integration.CPS; -import foundation.icon.icx.KeyWallet; -import foundation.icon.icx.Wallet; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import foundation.icon.score.client.DefaultScoreClient; -import org.junit.jupiter.api.*; -import score.Address; - -import java.math.BigInteger; -import java.util.Map; - -import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; -import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; - - -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class CPSTreasuryIntTest { - private static CPS cps; - private final KeyWallet tester = cps.user; - private final KeyWallet tester2 = cps.testUser; - - private final KeyWallet prepWallet1 = cps.prepWallet1; - private final KeyWallet prepWallet2 = cps.prepWallet2; - private final KeyWallet prepWallet3 = cps.prepWallet3; - private final KeyWallet prepWallet4 = cps.prepWallet4; - private final KeyWallet prepWallet5 = cps.prepWallet5; - private final KeyWallet prepWallet6 = cps.prepWallet6; - private final KeyWallet prepWallet7 = cps.prepWallet7; - public static final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L); - - private static Wallet owner; - - private static CPSTreasuryInterfaceScoreClient cpsTreasury; - private static CPFTreasuryInterfaceScoreClient cpfTreasury; - private static CPSCoreInterfaceScoreClient cpsMain; - - private static DexInterfaceScoreClient dex; - private static RouterInterfaceScoreClient router; - private static bnUSDInterfaceScoreClient bnusd; - private static sICXInterfaceScoreClient sicx; - - DefaultScoreClient clientWithTester = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , tester, cps.cpsCore._address()); - - DefaultScoreClient clientWithTester2 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , tester2, cps.cpsCore._address()); - - DefaultScoreClient prepClient1 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , prepWallet1, cps.cpsCore._address()); - - DefaultScoreClient bnUSDClient2 = new DefaultScoreClient(cps.bnusd.endpoint(), cps.bnusd._nid() - , prepWallet2, cps.bnusd._address()); - - - DefaultScoreClient prepClient2 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , prepWallet2, cps.cpsCore._address()); - DefaultScoreClient prepClient3 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , prepWallet3, cps.cpsCore._address()); - DefaultScoreClient prepClient4 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , prepWallet4, cps.cpsCore._address()); - DefaultScoreClient prepClient5 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , prepWallet5, cps.cpsCore._address()); - DefaultScoreClient prepClient6 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , prepWallet6, cps.cpsCore._address()); - DefaultScoreClient prepClient7 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() - , prepWallet7, cps.cpsCore._address()); - - @BeforeAll - static void setup() throws Exception { - cps = new CPS(); - cps.setupCPS(); - owner = cps.owner; - cpsMain = new CPSCoreInterfaceScoreClient(cps.cpsCore); - cpsTreasury = new CPSTreasuryInterfaceScoreClient(cps.cpsTreasury); - cpfTreasury = new CPFTreasuryInterfaceScoreClient(cps.cpfTreasury); - - dex = new DexInterfaceScoreClient(cps.dex); - bnusd = new bnUSDInterfaceScoreClient(cps.bnusd); - sicx = new sICXInterfaceScoreClient(cps.sicx); - router = new RouterInterfaceScoreClient(cps.router); - - } - - CPSCoreInterfaceScoreClient cpsMainTestClient1 = new CPSCoreInterfaceScoreClient(clientWithTester); - CPSCoreInterfaceScoreClient cpsMainTestClient2 = new CPSCoreInterfaceScoreClient(clientWithTester2); - CPSCoreInterfaceScoreClient prepSender1 = new CPSCoreInterfaceScoreClient(prepClient1); - bnUSDInterfaceScoreClient bnUSDSender2 = new bnUSDInterfaceScoreClient(bnUSDClient2); - CPSCoreInterfaceScoreClient prepSender2 = new CPSCoreInterfaceScoreClient(prepClient2); - CPSCoreInterfaceScoreClient prepSender3 = new CPSCoreInterfaceScoreClient(prepClient3); - CPSCoreInterfaceScoreClient prepSender4 = new CPSCoreInterfaceScoreClient(prepClient4); - CPSCoreInterfaceScoreClient prepSender5 = new CPSCoreInterfaceScoreClient(prepClient5); - CPSCoreInterfaceScoreClient prepSender6 = new CPSCoreInterfaceScoreClient(prepClient6); - CPSCoreInterfaceScoreClient prepSender7 = new CPSCoreInterfaceScoreClient(prepClient7); - - @Test - @Order(1) - void name(){ - assertEquals(cpsTreasury.name(), "CPS_TREASURY"); - assertEquals(cpfTreasury.name(), "CPF_TREASURY"); - assertEquals(cpsMain.name(), "CPS Score"); - } - - void addAdminMethod(){ - cpsMain.add_admin(Address.fromString(tester.getAddress().toString())); - cpsMain.add_admin(Address.fromString(owner.getAddress().toString())); - } - - private void setInitialBlockMethod(){ - cpsMain.set_initialBlock(); - } - - void setScores(){ - addAdminMethod(); - cpsMain.set_cps_treasury_score(cpsTreasury._address()); - assertEquals(cpsMain.getCpsTreasuryScore(), cpsTreasury._address()); - cpsMain.set_cpf_treasury_score(cpfTreasury._address()); - assertEquals(cpsMain.get_cpf_treasury_score(), cpfTreasury._address()); - cpsMain.set_bnUSD_score(bnusd._address()); - assertEquals(cpsMain.get_bnUSD_score(), bnusd._address()); - - cpsTreasury.setCpsScore(cpsMain._address()); - assertEquals(cpsTreasury.getCpsScore(), cpsMain._address()); - cpsTreasury.setCpfTreasuryScore(cpfTreasury._address()); - assertEquals(cpsTreasury.getCpfTreasuryScore(), cpfTreasury._address()); - cpsTreasury.setBnUSDScore(bnusd._address()); - assertEquals(cpsTreasury.getBnUSDScore(), bnusd._address()); - - cpfTreasury.setCpsScore(cpsMain._address()); - assertEquals(cpfTreasury.getCpsScore(), cpsMain._address()); - cpfTreasury.setCpsTreasuryScore(cpsTreasury._address()); - assertEquals(cpfTreasury.getCpsTreasuryScore(), cpsTreasury._address()); - cpfTreasury.setBnUSDScore(bnusd._address()); - assertEquals(cpfTreasury.getBnUSDScore(), bnusd._address()); - cpfTreasury.setRouterScore(router._address()); - assertEquals(cpfTreasury.getRouterScore(), router._address()); - cpfTreasury.setDexScore(dex._address()); - assertEquals(cpfTreasury.getDexScore(), dex._address()); - cpfTreasury.setSicxScore(sicx._address()); - assertEquals(cpfTreasury.getSicxScore(), sicx._address()); - - dex.setSicxScore(sicx._address()); - } - - void setCPFTreasuryContract(){ - setScores(); - cpfTreasury.setMaximumTreasuryFundBnusd(BigInteger.valueOf(1000).multiply(EXA)); - cpfTreasury.setMaximumTreasuryFundIcx(BigInteger.valueOf(1000).multiply(EXA)); - - cpfTreasury.add_fund(BigInteger.valueOf(1000).multiply(EXA)); - System.out.println(cpfTreasury.get_remaining_swap_amount()); - - setRouterScore(); - setDexScore(); - cpfTreasury.swapIcxBnusd(BigInteger.valueOf(200).multiply(EXA)); - System.out.println(bnusd.balanceOf(cpfTreasury._address())); - } - - void setRouterScore(){ +//package community.icon.cps.score.cpstreasury; +// +//import com.eclipsesource.json.JsonObject; +//import community.icon.cps.score.lib.interfaces.*; +// +//import community.icon.cps.score.test.integration.CPS; +//import foundation.icon.icx.KeyWallet; +//import foundation.icon.icx.Wallet; +//import static org.junit.jupiter.api.Assertions.assertEquals; +// +//import foundation.icon.score.client.DefaultScoreClient; +//import org.junit.jupiter.api.*; +//import score.Address; +// +//import java.math.BigInteger; +//import java.util.Map; +// +//import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; +//import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; +// +// +//@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +//public class CPSTreasuryIntTest { +// private static CPS cps; +// private final KeyWallet tester = cps.user; +// private final KeyWallet tester2 = cps.testUser; +// +// private final KeyWallet prepWallet1 = cps.prepWallet1; +// private final KeyWallet prepWallet2 = cps.prepWallet2; +// private final KeyWallet prepWallet3 = cps.prepWallet3; +// private final KeyWallet prepWallet4 = cps.prepWallet4; +// private final KeyWallet prepWallet5 = cps.prepWallet5; +// private final KeyWallet prepWallet6 = cps.prepWallet6; +// private final KeyWallet prepWallet7 = cps.prepWallet7; +// public static final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L); +// +// private static Wallet owner; +// +// private static CPSTreasuryInterfaceScoreClient cpsTreasury; +// private static CPFTreasuryInterfaceScoreClient cpfTreasury; +// private static CPSCoreInterfaceScoreClient cpsMain; +// +// private static DexInterfaceScoreClient dex; +// private static RouterInterfaceScoreClient router; +// private static bnUSDInterfaceScoreClient bnusd; +// private static sICXInterfaceScoreClient sicx; +// +// DefaultScoreClient clientWithTester = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , tester, cps.cpsCore._address()); +// +// DefaultScoreClient clientWithTester2 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , tester2, cps.cpsCore._address()); +// +// DefaultScoreClient prepClient1 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , prepWallet1, cps.cpsCore._address()); +// +// DefaultScoreClient bnUSDClient2 = new DefaultScoreClient(cps.bnusd.endpoint(), cps.bnusd._nid() +// , prepWallet2, cps.bnusd._address()); +// +// +// DefaultScoreClient prepClient2 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , prepWallet2, cps.cpsCore._address()); +// DefaultScoreClient prepClient3 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , prepWallet3, cps.cpsCore._address()); +// DefaultScoreClient prepClient4 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , prepWallet4, cps.cpsCore._address()); +// DefaultScoreClient prepClient5 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , prepWallet5, cps.cpsCore._address()); +// DefaultScoreClient prepClient6 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , prepWallet6, cps.cpsCore._address()); +// DefaultScoreClient prepClient7 = new DefaultScoreClient(cps.cpsCore.endpoint(), cps.cpsCore._nid() +// , prepWallet7, cps.cpsCore._address()); +// +// @BeforeAll +// static void setup() throws Exception { +// cps = new CPS(); +// cps.setupCPS(); +// owner = cps.owner; +// cpsMain = new CPSCoreInterfaceScoreClient(cps.cpsCore); +// cpsTreasury = new CPSTreasuryInterfaceScoreClient(cps.cpsTreasury); +// cpfTreasury = new CPFTreasuryInterfaceScoreClient(cps.cpfTreasury); +// +// dex = new DexInterfaceScoreClient(cps.dex); +// bnusd = new bnUSDInterfaceScoreClient(cps.bnusd); +// sicx = new sICXInterfaceScoreClient(cps.sicx); +// router = new RouterInterfaceScoreClient(cps.router); +// +// } +// +// CPSCoreInterfaceScoreClient cpsMainTestClient1 = new CPSCoreInterfaceScoreClient(clientWithTester); +// CPSCoreInterfaceScoreClient cpsMainTestClient2 = new CPSCoreInterfaceScoreClient(clientWithTester2); +// CPSCoreInterfaceScoreClient prepSender1 = new CPSCoreInterfaceScoreClient(prepClient1); +// bnUSDInterfaceScoreClient bnUSDSender2 = new bnUSDInterfaceScoreClient(bnUSDClient2); +// CPSCoreInterfaceScoreClient prepSender2 = new CPSCoreInterfaceScoreClient(prepClient2); +// CPSCoreInterfaceScoreClient prepSender3 = new CPSCoreInterfaceScoreClient(prepClient3); +// CPSCoreInterfaceScoreClient prepSender4 = new CPSCoreInterfaceScoreClient(prepClient4); +// CPSCoreInterfaceScoreClient prepSender5 = new CPSCoreInterfaceScoreClient(prepClient5); +// CPSCoreInterfaceScoreClient prepSender6 = new CPSCoreInterfaceScoreClient(prepClient6); +// CPSCoreInterfaceScoreClient prepSender7 = new CPSCoreInterfaceScoreClient(prepClient7); +// +// @Test +// @Order(1) +// void name(){ +// assertEquals(cpsTreasury.name(), "CPS_TREASURY"); +// assertEquals(cpfTreasury.name(), "CPF_TREASURY"); +// assertEquals(cpsMain.name(), "CPS Score"); +// } +// +// void addAdminMethod(){ +// cpsMain.add_admin(Address.fromString(tester.getAddress().toString())); +// cpsMain.add_admin(Address.fromString(owner.getAddress().toString())); +// } +// +// private void setInitialBlockMethod(){ +// cpsMain.set_initialBlock(); +// } +// +// void setScores(){ +// addAdminMethod(); +// cpsMain.set_cps_treasury_score(cpsTreasury._address()); +// assertEquals(cpsMain.getCpsTreasuryScore(), cpsTreasury._address()); +// cpsMain.set_cpf_treasury_score(cpfTreasury._address()); +// assertEquals(cpsMain.get_cpf_treasury_score(), cpfTreasury._address()); +// cpsMain.set_bnUSD_score(bnusd._address()); +// assertEquals(cpsMain.get_bnUSD_score(), bnusd._address()); +// +// cpsTreasury.setCpsScore(cpsMain._address()); +// assertEquals(cpsTreasury.getCpsScore(), cpsMain._address()); +// cpsTreasury.setCpfTreasuryScore(cpfTreasury._address()); +// assertEquals(cpsTreasury.getCpfTreasuryScore(), cpfTreasury._address()); +// cpsTreasury.setBnUSDScore(bnusd._address()); +// assertEquals(cpsTreasury.getBnUSDScore(), bnusd._address()); +// +// cpfTreasury.setCpsScore(cpsMain._address()); +// assertEquals(cpfTreasury.getCpsScore(), cpsMain._address()); +// cpfTreasury.setCpsTreasuryScore(cpsTreasury._address()); +// assertEquals(cpfTreasury.getCpsTreasuryScore(), cpsTreasury._address()); +// cpfTreasury.setBnUSDScore(bnusd._address()); +// assertEquals(cpfTreasury.getBnUSDScore(), bnusd._address()); +// cpfTreasury.setRouterScore(router._address()); +// assertEquals(cpfTreasury.getRouterScore(), router._address()); +// cpfTreasury.setDexScore(dex._address()); +// assertEquals(cpfTreasury.getDexScore(), dex._address()); +// cpfTreasury.setSicxScore(sicx._address()); +// assertEquals(cpfTreasury.getSicxScore(), sicx._address()); +// +// dex.setSicxScore(sicx._address()); +// } +// +// void setCPFTreasuryContract(){ // setScores(); - bnusd.transfer(router._address(), BigInteger.valueOf(100000).multiply(EXA), null); - bnusd.transfer(Address.fromString(prepWallet2.getAddress().toString()), BigInteger.valueOf(1000).multiply(EXA), null); - System.out.println(bnusd.balanceOf(router._address())); - } - - void setDexScore(){ -// setScores(); - sicx.transfer(dex._address(), BigInteger.valueOf(100000).multiply(EXA), null); - System.out.println(sicx.balanceOf(dex._address())); - } - - private void registerPrepMethod(){ - setInitialBlockMethod(); - cpsMain.toggle_maintenance(); - prepSender1.register_prep(); - prepSender2.register_prep(); - prepSender3.register_prep(); - prepSender4.register_prep(); - prepSender5.register_prep(); - prepSender6.register_prep(); - prepSender7.register_prep(); - } - - @Test - @Order(2) - void submitProposal(){ - setCPFTreasuryContract(); - registerPrepMethod(); - ProposalAttributes proposalAttributes = new ProposalAttributes(); - proposalAttributes.ipfs_hash = "Proposal 1"; - proposalAttributes.project_title = "Proposal 1 title"; - proposalAttributes.ipfs_link = "Link"; - proposalAttributes.project_duration = 3; - proposalAttributes.token = "bnUSD"; - proposalAttributes.sponsor_address = Address.fromString(prepWallet2.getAddress().toString()); - proposalAttributes.total_budget = BigInteger.valueOf(100); - - cpsMain.submit_proposal(BigInteger.valueOf(50).multiply(EXA), proposalAttributes); - - Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); - assertEquals(proposalDetails.get("ipfs_hash"), "Proposal 1"); - assertEquals(proposalDetails.get("project_duration"), "0x" + Integer.toHexString(3)); - assertEquals(proposalDetails.get("project_title"), "Proposal 1 title"); - assertEquals(proposalDetails.get("status"), "_sponsor_pending"); - assertEquals(proposalDetails.get("token"), "bnUSD"); - String totalBudgetString = ((String) proposalDetails.get("total_budget")).substring(2); - assertEquals(new BigInteger(totalBudgetString, 16), BigInteger.valueOf(100).multiply(EXA)); - } - - @Test - @Order(3) - void voteProposal(){ - JsonObject sponsorVoteParams = new JsonObject(); - sponsorVoteParams.add("method", "sponsor_vote"); - JsonObject params = new JsonObject(); - params.add("ipfs_hash", "Proposal 1"); - params.add("vote", "_accept"); - params.add("vote_reason", "sponsor_reason"); - sponsorVoteParams.add("params", params); - logger("sponsor vote start"); - bnUSDSender2.transfer(cpsMain._address(), BigInteger.valueOf(10).multiply(EXA), sponsorVoteParams.toString().getBytes()); - logger("sponosr vote complete"); - - cpsMain.update_next_block(0); - logger("period ended"); - - cpsMain.update_period(); - logger("updated to next period"); - - prepSender1.vote_proposal("Proposal 1", "_approve", "reason", false); - prepSender2.vote_proposal("Proposal 1", "_approve", "reason", false); - prepSender3.vote_proposal("Proposal 1", "_approve", "reason", false); - prepSender4.vote_proposal("Proposal 1", "_approve", "reason", false); - prepSender5.vote_proposal("Proposal 1", "_approve", "reason", false); - prepSender6.vote_proposal("Proposal 1", "_reject", "reason", false); - prepSender7.vote_proposal("Proposal 1", "_reject", "reason", false); - - logger("completed vote"); - - Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); - logger(proposalDetails); - - assertEquals("0x" + Integer.toHexString(5), proposalDetails.get("approve_voters")); - assertEquals("0x" + Integer.toHexString(2), proposalDetails.get("reject_voters")); - assertEquals("0x" + Integer.toHexString(7), proposalDetails.get("total_voters")); - assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String) proposalDetails.get("approved_votes")).substring(2), 16)); - assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String) proposalDetails.get("rejected_votes")).substring(2), 16)); - assertEquals(BigInteger.valueOf(5600).multiply(EXA), new BigInteger(((String) proposalDetails.get("total_votes")).substring(2), 16)); - } - - @Test - @Order(4) - void votePriority(){ - String[] priorityVote = {"Proposal 1"}; - logger("priority voting started"); - prepSender1.votePriority(priorityVote); - prepSender2.votePriority(priorityVote); - prepSender3.votePriority(priorityVote); - prepSender4.votePriority(priorityVote); - prepSender5.votePriority(priorityVote); - prepSender6.votePriority(priorityVote); - prepSender7.votePriority(priorityVote); - logger("priority vote complete"); - Map priorityVoteResult = cpsMain.getPriorityVoteResult(); - logger(priorityVoteResult); - assertEquals(7, priorityVoteResult.get("Proposal 1")); - } - - @Test - @Order(5) - void updatePeriodAfterVoting(){ - cpsMain.update_next_block(0); - logger("end period"); - - cpsMain.update_period(); - logger("end first update period period"); - - cpsMain.update_period(); - logger("end second update period period"); - - cpsMain.update_period(); - logger("end third update period period"); - - cpsMain.update_period(); - logger("end fourth update period period"); - - Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); - logger(proposalDetails); - - assertEquals("bond_approved", proposalDetails.get("sponsor_deposit_status")); - assertEquals("_active", proposalDetails.get("status")); - } - - @Test - @Order(6) - void submitProgressReport(){ - ProgressReportAttributes progress = new ProgressReportAttributes(); - progress.ipfs_hash = "Proposal 1"; - progress.report_hash = "Report 1"; - progress.progress_report_title = "Progress Report Title"; - progress.ipfs_link = "Link"; - progress.additional_budget = BigInteger.valueOf(50); - progress.budget_adjustment = Boolean.TRUE; - progress.percentage_completed = 10; - progress.additional_month = 2; - cpsMain.toggleBudgetAdjustmentFeature(); - cpsMain.submit_progress_report(progress); - - Map progressReports = cpsMain.get_progress_reports_by_hash("Report 1"); - logger(progressReports); - - assertEquals("Report 1", progressReports.get("report_hash")); - assertEquals("_waiting", progressReports.get("status")); - assertEquals("Progress Report Title", progressReports.get("progress_report_title")); - assertEquals("Proposal 1", progressReports.get("ipfs_hash")); - assertEquals("_pending", progressReports.get("budget_adjustment_status")); - assertEquals("0x" + Integer.toHexString(2), progressReports.get("additional_month")); - assertEquals(BigInteger.valueOf(50).multiply(EXA), new BigInteger(((String)progressReports.get("additional_budget")).substring(2), 16)); - } - - @Test - @Order(7) - void vote_progress_report(){ - cpsMain.update_next_block(0); - logger("period ended"); - - logger(cpsMain.get_PReps()); - - cpsMain.update_period(); - logger("updated to next period"); - - logger(cpsMain.get_period_status()); - - prepSender1.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); - prepSender2.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); - prepSender3.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); - prepSender4.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); - prepSender5.vote_progress_report("Proposal 1", "Report 1", "_reject", "vote reason", "_reject", false); - prepSender6.vote_progress_report("Proposal 1", "Report 1", "_reject", "vote reason", "_reject", false); - prepSender7.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); - - logger("completed vote"); - - Map progressReports = cpsMain.get_progress_reports_by_hash("Report 1"); - logger(progressReports); - - assertEquals(BigInteger.valueOf(5600).multiply(EXA), new BigInteger(((String)progressReports.get("total_votes")).substring(2), 16)); - assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String)progressReports.get("approved_votes")).substring(2), 16)); - assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String)progressReports.get("rejected_votes")).substring(2), 16)); - assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String)progressReports.get("budget_approved_votes")).substring(2), 16)); - assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String)progressReports.get("budget_rejected_votes")).substring(2), 16)); - assertEquals("0x" + Integer.toHexString(7), progressReports.get("total_voters")); - assertEquals("0x" + Integer.toHexString(5), progressReports.get("approve_voters")); - assertEquals("0x" + Integer.toHexString(2), progressReports.get("reject_voters")); - assertEquals("0x" + Integer.toHexString(5), progressReports.get("budget_approve_voters")); - assertEquals("0x" + Integer.toHexString(2), progressReports.get("budget_reject_voters")); - } - - @Test - @Order(8) - void update_period_after_voting_progress_reports(){ - cpsMain.update_next_block(0); - logger("end period"); - - cpsMain.update_period(); - logger("end first update period period"); - - cpsMain.update_period(); - logger("end second update period period"); - - cpsMain.update_period(); - logger("end third update period period"); - - cpsMain.update_period(); - logger("end fourth update period period"); - - Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); - logger(proposalDetails); - - Map progressDetails = cpsMain.get_progress_reports_by_hash("Report 1"); - logger(progressDetails); - } - void logger(T log){ - System.out.println(log); - } - - -} +// cpfTreasury.setMaximumTreasuryFundBnusd(BigInteger.valueOf(1000).multiply(EXA)); +// cpfTreasury.setMaximumTreasuryFundIcx(BigInteger.valueOf(1000).multiply(EXA)); +// +// cpfTreasury.add_fund(BigInteger.valueOf(1000).multiply(EXA)); +// System.out.println(cpfTreasury.get_remaining_swap_amount()); +// +// setRouterScore(); +// setDexScore(); +// cpfTreasury.swapIcxBnusd(BigInteger.valueOf(200).multiply(EXA)); +// System.out.println(bnusd.balanceOf(cpfTreasury._address())); +// } +// +// void setRouterScore(){ +//// setScores(); +// bnusd.transfer(router._address(), BigInteger.valueOf(100000).multiply(EXA), null); +// bnusd.transfer(Address.fromString(prepWallet2.getAddress().toString()), BigInteger.valueOf(1000).multiply(EXA), null); +// System.out.println(bnusd.balanceOf(router._address())); +// } +// +// void setDexScore(){ +//// setScores(); +// sicx.transfer(dex._address(), BigInteger.valueOf(100000).multiply(EXA), null); +// System.out.println(sicx.balanceOf(dex._address())); +// } +// +// private void registerPrepMethod(){ +// setInitialBlockMethod(); +// cpsMain.toggle_maintenance(); +// prepSender1.register_prep(); +// prepSender2.register_prep(); +// prepSender3.register_prep(); +// prepSender4.register_prep(); +// prepSender5.register_prep(); +// prepSender6.register_prep(); +// prepSender7.register_prep(); +// } +// +// @Test +// @Order(2) +// void submitProposal(){ +// setCPFTreasuryContract(); +// registerPrepMethod(); +// ProposalAttributes proposalAttributes = new ProposalAttributes(); +// proposalAttributes.ipfs_hash = "Proposal 1"; +// proposalAttributes.project_title = "Proposal 1 title"; +// proposalAttributes.ipfs_link = "Link"; +// proposalAttributes.project_duration = 3; +// proposalAttributes.token = "bnUSD"; +// proposalAttributes.sponsor_address = Address.fromString(prepWallet2.getAddress().toString()); +// proposalAttributes.total_budget = BigInteger.valueOf(100); +// +// cpsMain.submit_proposal(BigInteger.valueOf(50).multiply(EXA), proposalAttributes); +// +// Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); +// assertEquals(proposalDetails.get("ipfs_hash"), "Proposal 1"); +// assertEquals(proposalDetails.get("project_duration"), "0x" + Integer.toHexString(3)); +// assertEquals(proposalDetails.get("project_title"), "Proposal 1 title"); +// assertEquals(proposalDetails.get("status"), "_sponsor_pending"); +// assertEquals(proposalDetails.get("token"), "bnUSD"); +// String totalBudgetString = ((String) proposalDetails.get("total_budget")).substring(2); +// assertEquals(new BigInteger(totalBudgetString, 16), BigInteger.valueOf(100).multiply(EXA)); +// } +// +// @Test +// @Order(3) +// void voteProposal(){ +// JsonObject sponsorVoteParams = new JsonObject(); +// sponsorVoteParams.add("method", "sponsor_vote"); +// JsonObject params = new JsonObject(); +// params.add("ipfs_hash", "Proposal 1"); +// params.add("vote", "_accept"); +// params.add("vote_reason", "sponsor_reason"); +// sponsorVoteParams.add("params", params); +// logger("sponsor vote start"); +// bnUSDSender2.transfer(cpsMain._address(), BigInteger.valueOf(10).multiply(EXA), sponsorVoteParams.toString().getBytes()); +// logger("sponosr vote complete"); +// +// cpsMain.update_next_block(0); +// logger("period ended"); +// +// cpsMain.update_period(); +// logger("updated to next period"); +// +// prepSender1.vote_proposal("Proposal 1", "_approve", "reason", false); +// prepSender2.vote_proposal("Proposal 1", "_approve", "reason", false); +// prepSender3.vote_proposal("Proposal 1", "_approve", "reason", false); +// prepSender4.vote_proposal("Proposal 1", "_approve", "reason", false); +// prepSender5.vote_proposal("Proposal 1", "_approve", "reason", false); +// prepSender6.vote_proposal("Proposal 1", "_reject", "reason", false); +// prepSender7.vote_proposal("Proposal 1", "_reject", "reason", false); +// +// logger("completed vote"); +// +// Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); +// logger(proposalDetails); +// +// assertEquals("0x" + Integer.toHexString(5), proposalDetails.get("approve_voters")); +// assertEquals("0x" + Integer.toHexString(2), proposalDetails.get("reject_voters")); +// assertEquals("0x" + Integer.toHexString(7), proposalDetails.get("total_voters")); +// assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String) proposalDetails.get("approved_votes")).substring(2), 16)); +// assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String) proposalDetails.get("rejected_votes")).substring(2), 16)); +// assertEquals(BigInteger.valueOf(5600).multiply(EXA), new BigInteger(((String) proposalDetails.get("total_votes")).substring(2), 16)); +// } +// +// @Test +// @Order(4) +// void votePriority(){ +// String[] priorityVote = {"Proposal 1"}; +// logger("priority voting started"); +// prepSender1.votePriority(priorityVote); +// prepSender2.votePriority(priorityVote); +// prepSender3.votePriority(priorityVote); +// prepSender4.votePriority(priorityVote); +// prepSender5.votePriority(priorityVote); +// prepSender6.votePriority(priorityVote); +// prepSender7.votePriority(priorityVote); +// logger("priority vote complete"); +// Map priorityVoteResult = cpsMain.getPriorityVoteResult(); +// logger(priorityVoteResult); +// assertEquals(7, priorityVoteResult.get("Proposal 1")); +// } +// +// @Test +// @Order(5) +// void updatePeriodAfterVoting(){ +// cpsMain.update_next_block(0); +// logger("end period"); +// +// cpsMain.update_period(); +// logger("end first update period period"); +// +// cpsMain.update_period(); +// logger("end second update period period"); +// +// cpsMain.update_period(); +// logger("end third update period period"); +// +// cpsMain.update_period(); +// logger("end fourth update period period"); +// +// Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); +// logger(proposalDetails); +// +// assertEquals("bond_approved", proposalDetails.get("sponsor_deposit_status")); +// assertEquals("_active", proposalDetails.get("status")); +// } +// +// @Test +// @Order(6) +// void submitProgressReport(){ +// ProgressReportAttributes progress = new ProgressReportAttributes(); +// progress.ipfs_hash = "Proposal 1"; +// progress.report_hash = "Report 1"; +// progress.progress_report_title = "Progress Report Title"; +// progress.ipfs_link = "Link"; +// progress.additional_budget = BigInteger.valueOf(50); +// progress.budget_adjustment = Boolean.TRUE; +// progress.percentage_completed = 10; +// progress.additional_month = 2; +// cpsMain.toggleBudgetAdjustmentFeature(); +// cpsMain.submit_progress_report(progress); +// +// Map progressReports = cpsMain.get_progress_reports_by_hash("Report 1"); +// logger(progressReports); +// +// assertEquals("Report 1", progressReports.get("report_hash")); +// assertEquals("_waiting", progressReports.get("status")); +// assertEquals("Progress Report Title", progressReports.get("progress_report_title")); +// assertEquals("Proposal 1", progressReports.get("ipfs_hash")); +// assertEquals("_pending", progressReports.get("budget_adjustment_status")); +// assertEquals("0x" + Integer.toHexString(2), progressReports.get("additional_month")); +// assertEquals(BigInteger.valueOf(50).multiply(EXA), new BigInteger(((String)progressReports.get("additional_budget")).substring(2), 16)); +// } +// +// @Test +// @Order(7) +// void vote_progress_report(){ +// cpsMain.update_next_block(0); +// logger("period ended"); +// +// logger(cpsMain.get_PReps()); +// +// cpsMain.update_period(); +// logger("updated to next period"); +// +// logger(cpsMain.get_period_status()); +// +// prepSender1.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); +// prepSender2.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); +// prepSender3.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); +// prepSender4.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); +// prepSender5.vote_progress_report("Proposal 1", "Report 1", "_reject", "vote reason", "_reject", false); +// prepSender6.vote_progress_report("Proposal 1", "Report 1", "_reject", "vote reason", "_reject", false); +// prepSender7.vote_progress_report("Proposal 1", "Report 1", "_approve", "vote reason", "_approve", false); +// +// logger("completed vote"); +// +// Map progressReports = cpsMain.get_progress_reports_by_hash("Report 1"); +// logger(progressReports); +// +// assertEquals(BigInteger.valueOf(5600).multiply(EXA), new BigInteger(((String)progressReports.get("total_votes")).substring(2), 16)); +// assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String)progressReports.get("approved_votes")).substring(2), 16)); +// assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String)progressReports.get("rejected_votes")).substring(2), 16)); +// assertEquals(BigInteger.valueOf(4000).multiply(EXA), new BigInteger(((String)progressReports.get("budget_approved_votes")).substring(2), 16)); +// assertEquals(BigInteger.valueOf(1600).multiply(EXA), new BigInteger(((String)progressReports.get("budget_rejected_votes")).substring(2), 16)); +// assertEquals("0x" + Integer.toHexString(7), progressReports.get("total_voters")); +// assertEquals("0x" + Integer.toHexString(5), progressReports.get("approve_voters")); +// assertEquals("0x" + Integer.toHexString(2), progressReports.get("reject_voters")); +// assertEquals("0x" + Integer.toHexString(5), progressReports.get("budget_approve_voters")); +// assertEquals("0x" + Integer.toHexString(2), progressReports.get("budget_reject_voters")); +// } +// +// @Test +// @Order(8) +// void update_period_after_voting_progress_reports(){ +// cpsMain.update_next_block(0); +// logger("end period"); +// +// cpsMain.update_period(); +// logger("end first update period period"); +// +// cpsMain.update_period(); +// logger("end second update period period"); +// +// cpsMain.update_period(); +// logger("end third update period period"); +// +// cpsMain.update_period(); +// logger("end fourth update period period"); +// +// Map proposalDetails = cpsMain.get_proposal_details_by_hash("Proposal 1"); +// logger(proposalDetails); +// +// Map progressDetails = cpsMain.get_progress_reports_by_hash("Report 1"); +// logger(progressDetails); +// } +// void logger(T log){ +// System.out.println(log); +// } +// +// +//} From 26960c37e6efa009e01abb9fe48dbe7a276acce5 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Sat, 19 Nov 2022 11:11:00 +0545 Subject: [PATCH 086/112] added getOrDefault in id and added admin check in migration script --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 01811924..3651eeac 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -87,7 +87,7 @@ private String getId() { } private String proposalPrefix(String _proposal_key) { - return PROPOSAL_DB_PREFIX + "|" + id.get() + "|" + _proposal_key; + return PROPOSAL_DB_PREFIX + "|" + id.getOrDefault("") + "|" + _proposal_key; } private Boolean proposalExists(String _ipfs_key) { @@ -483,6 +483,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { @Override @External public void updateSponsorAndContributorProjects(){ + validateAdmins(); for (int i = 0; i < proposalsKeys.size(); i++){ String proposalKey = proposalsKeys.get(i); String proposalPrefix = proposalPrefix(proposalKey); From fe7361f433e512feb6cf2d56ca0d789ee455ac97 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 22 Nov 2022 15:13:14 +0545 Subject: [PATCH 087/112] Remove unused variables --- .../cps/score/cpstreasury/utils/consts.java | 107 +----------------- 1 file changed, 2 insertions(+), 105 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java index 16eeb4f5..a84965ef 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/consts.java @@ -3,116 +3,13 @@ import java.math.BigInteger; public class consts { - public consts(){} - //# ICX Multiplier - public static final BigInteger MULTIPLIER = BigInteger.valueOf(10^18); - // # MAXIMUM PROJECT PERIOD - public static final int MAX_PROJECT_PERIOD = 6; + public consts() { + } - //# 2/3 Vot - public static final double MAJORITY = 0.67; - - //# Period Interval Time - public static final int DAY_COUNT = 15; - - //# Total Blocks in 1 day - public static final int BLOCKS_DAY_COUNT = 20; - - //# User Defined Db - // PROPOSAL_DB_PREFIX = b'iconbetProposal' - // PROGRESS_REPORT_DB_PREFIX = b'progressReport' - - // # Period Names - public static final String APPLICATION_PERIOD = "Application Period"; - public static final String VOTING_PERIOD = "Voting Period"; - public static final String TRANSITION_PERIOD = "Transition Period"; - - // # SCOREs Constants - public static final String DAOFUND_SCORE = "_daofund_score"; - public static final String TAP_TOKEN_SCORE = "_tap_token_score"; - public static final String PROPOSALS_FUND_SCORE = "_proposals_fund_score"; - - // # PERIOD CONSTANTS - public static final String INITIAL_BLOCK = "initial_block"; - public static final String PERIOD_DETAILS = "_period_details"; - public static final String PERIOD_NAME = "period_name"; - public static final String PREVIOUS_PERIOD_NAME = "previous_period_name"; - public static final String PERIOD_SPAN = "period_span"; - public static final String LASTBLOCK = "last_block"; - public static final String CURRENTBLOCK = "current_block"; - public static final String NEXTBLOCK = "next_block"; - public static final String REMAINING_TIME = "remaining_time"; - public static final String UPDATE_PERIOD_INDEX = "update_period_index"; - - // #Admins - public static final String ADMINS = "admins"; - - //# VarDB/ArrayDB Params - public static final String PROPOSALS_KEY_LIST = "proposals_key_list"; - public static final String PROGRESS_KEY_LIST = "progress_key_list"; - public static final String PROPOSERS = "proposers"; - public static final String BUDGET_APPROVALS_LIST = "budget_approvals_list"; public static final String TOTAL_BUDGET = "total_budget"; - public static final String ACTIVE_PROPOSALS = "active_proposals"; - public static final String VOTING_PROPOSALS = "voting_proposals"; - public static final String VOTING_PROGRESS_REPORTS = "voting_progress_reports"; - public static final String AMOUNT = "_total_amount"; - public static final String ADDRESS = "address"; - - // # Proposals and Progress reports keys - public static final String PROPOSAL = "proposal"; - public static final String PROGRESS_REPORTS = "progress_report"; - public static final String NEW_PROGRESS_REPORT = "new_progress_report"; - public static final String PROJECT_TYPE = "project_type"; - public static final String PROJECT_TITLE = "project_title"; - public static final String PROGRESS_REPORT_TITLE = "progress_report_title"; - public static final String TOTAL_VOTES = "total_votes"; - public static final String TOTAL_VOTERS = "total_voters"; - public static final String REJECTED_VOTES = "rejected_votes"; - public static final String APPROVED_VOTES = "approved_votes"; - public static final String REJECT_VOTERS = "reject_voters"; - public static final String APPROVE_VOTERS = "approve_voters"; - - public static final String TIMESTAMP = "timestamp"; - public static final String PROPOSER_ADDRESS = "proposer_address"; - public static final String TX_HASH = "tx_hash"; public static final String IPFS_HASH = "ipfs_hash"; - public static final String REPORT_KEY = "report_key"; - public static final String REPORT_HASH = "report_hash"; public static final String PROJECT_DURATION = "project_duration"; - public static final String APPROVED_REPORTS = "approved_reports"; - public static final String IPFS_LINK = "ipfs_link"; - public static final String PERCENTAGE_COMPLETED = "percentage_completed"; - public static final String SUBMIT_PROGRESS_REPORT = "submit_progress_report"; - public static final String ADDITIONAL_BUDGET = "additional_budget"; - public static final String ADDITIONAL_DURATION = "additional_month"; - public static final String BUDGET_ADJUSTMENT = "budget_adjustment"; - public static final String BUDGET_ADJUSTMENT_STATUS = "budget_adjustment_status"; - public static final String BUDGET_APPROVED_VOTES = "budget_approved_votes"; - public static final String BUDGET_REJECTED_VOTES = "budget_rejected_votes"; - public static final String BUDGET_APPROVE_VOTERS = "budget_approve_voters"; - public static final String BUDGET_REJECT_VOTERS = "budget_reject_voters"; - - - - - public static final String DENYLIST = "denylist"; - public static final String PENALTY_AMOUNT = "penalty_amount"; public static final String STATUS = "status"; - public static final String DATA = "data"; - public static final String COUNT = "count"; - - // # VOTE KEYS - public static final String VOTE = "vote"; - public static final String VOTE_REASON = "vote_reason"; - public static final String APPROVE = "_approve"; - public static final String REJECT = "_reject"; - public static final String ABSTAIN = "_abstain"; - public static final String ACCEPT = "_accept"; - - // # MINIMUM TAP - public static final BigInteger MINIMUM_TAP_TO_SUBMIT_PROPOSAL = BigInteger.valueOf(10000).multiply(MULTIPLIER); - public static final BigInteger MINIMUM_TAP_TO_VOTE = BigInteger.valueOf(10 ^ 18); public static final String ICX = "ICX"; public static final String bnUSD = "bnUSD"; From 2e3e4a7f02da367b5b30b354e41842d0fe050c4f Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 22 Nov 2022 15:13:28 +0545 Subject: [PATCH 088/112] Remove unused getMethods --- .../score/cpstreasury/db/ProposalData.java | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java index f9ae7de4..1eb43b95 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java @@ -71,10 +71,6 @@ public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ ); } - public String getIpfsHash(String prefix){ - return ipfsHash.at(prefix).get(); - } - public Address getSponsorAddress(String prefix){ return sponsorAddress.at(prefix).get(); } @@ -103,10 +99,6 @@ public void setProjectDuration(String prefix, int projectDuration){ this.projectDuration.at(prefix).set(projectDuration); } - public int getProjectDuration(String prefix){ - return projectDuration.at(prefix).getOrDefault(0); - } - public void setWithdrawAmount(String prefix, BigInteger withdrawAmount){ this.withdrawAmount.at(prefix).set(withdrawAmount); } @@ -119,10 +111,6 @@ public void setInstallmentCount(String prefix, int installmentCount){ this.installmentCount.at(prefix).set(installmentCount); } - public int getInstallmentCount(String prefix){ - return installmentCount.at(prefix).getOrDefault(0); - } - public void setSponsorRewardCount(String prefix, int sponsorRewardCount){ this.sponsorRewardCount.at(prefix).set(sponsorRewardCount); } @@ -142,11 +130,6 @@ public BigInteger getSponsorWithdrawAmount(String prefix){ public void setRemainingAmount(String prefix, BigInteger remainingAmount){ this.remainingAmount.at(prefix).set(remainingAmount); } - - public BigInteger getRemainingAmount(String prefix){ - return remainingAmount.at(prefix).getOrDefault(BigInteger.ZERO); - } - public void setSponsorRemainingAmount(String prefix, BigInteger sponsorRemainingAmount){ this.sponsorRemainingAmount.at(prefix).set(sponsorRemainingAmount); } @@ -159,10 +142,6 @@ public void setStatus(String prefix, String status){ this.status.at(prefix).set(status); } - public String getStatus(String prefix){ - return status.at(prefix).get(); - } - public String getToken(String prefix){ return token.at(prefix).get(); } From ef36eaee52493e1eca909707db38401cc0b5cf37 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 22 Nov 2022 15:21:46 +0545 Subject: [PATCH 089/112] Remove use of unused `id` --- .../community/icon/cps/score/cpstreasury/CPSTreasury.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 3651eeac..272d9fb3 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -20,8 +20,6 @@ public class CPSTreasury extends ProposalData implements CPSTreasuryInterface{ private static final String TAG = "CPS_TREASURY"; private static final String PROPOSAL_DB_PREFIX = "proposal"; - - private static final String ID = "id"; private static final String PROPOSALS_KEYS = "_proposals_keys"; private static final String PROPOSALS_KEY_LIST_INDEX = "proposals_key_list_index"; private static final String FUND_RECORD = "fund_record"; @@ -51,7 +49,6 @@ public class CPSTreasury extends ProposalData implements CPSTreasuryInterface{ private static final String CONTRIBUTOR_PROJECTS = "contributor_projects"; private static final String SPONSOR_PROJECTS = "sponsor_projects"; - private final VarDB id = Context.newVarDB(ID, String.class); private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); private final DictDB proposalsKeyListIndex = Context.newDictDB(PROPOSALS_KEY_LIST_INDEX, Integer.class); private final DictDB fundRecord = Context.newDictDB(FUND_RECORD, BigInteger.class); @@ -87,7 +84,7 @@ private String getId() { } private String proposalPrefix(String _proposal_key) { - return PROPOSAL_DB_PREFIX + "|" + id.getOrDefault("") + "|" + _proposal_key; + return PROPOSAL_DB_PREFIX + "|" + "|" + _proposal_key; } private Boolean proposalExists(String _ipfs_key) { From 17fb480871b4f5493348c82fa04e0535caedbf21 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 22 Nov 2022 15:22:40 +0545 Subject: [PATCH 090/112] optimize and implement batch mode for data migration --- .../icon/cps/score/cpstreasury/CPSTreasury.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 272d9fb3..9da9c073 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -59,6 +59,7 @@ public class CPSTreasury extends ProposalData implements CPSTreasuryInterface{ private final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS, String.class); private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS, String.class); + private final VarDB batchSize = Context.newVarDB("batch_size", Integer.class); public CPSTreasury() { } @@ -481,13 +482,20 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { @External public void updateSponsorAndContributorProjects(){ validateAdmins(); - for (int i = 0; i < proposalsKeys.size(); i++){ + int startIndex = batchSize.getOrDefault(0); + int size = proposalsKeys.size(); + int endIndex = startIndex + 10; + if (endIndex > size) { + endIndex = size; + } + for (int i = startIndex; i < endIndex; i++) { String proposalKey = proposalsKeys.get(i); String proposalPrefix = proposalPrefix(proposalKey); Address contributorAddress = getContributorAddress(proposalPrefix); Address sponsorAddress = getSponsorAddress(proposalPrefix); contributorProjects.at(contributorAddress.toString()).add(proposalKey); sponsorProjects.at(sponsorAddress.toString()).add(proposalKey); + batchSize.set(endIndex); } } From 5a09fdb20157f04e67b8454f55a58b4bc327e8a5 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 22 Nov 2022 15:23:20 +0545 Subject: [PATCH 091/112] implement migrated data on get methods --- .../icon/cps/score/cpstreasury/CPSTreasury.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 9da9c073..3d58e406 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -168,8 +168,10 @@ public Address getBnUSDScore() { BigInteger totalAmountToBePaidICX = BigInteger.ZERO; BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; List> projectDetails = new ArrayList<>(); - for (int i = 0; i < proposalsKeys.size(); i++) { - String _ipfs_key = proposalsKeys.get(i); + ArrayDB proposalKeysArray = contributorProjects.at(_wallet_address.toString()); + int proposalKeysSize = proposalKeysArray.size(); + for (int i = 0; i < proposalKeysSize; i++) { + String _ipfs_key = proposalKeysArray.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); // todo: getting entire proposal details or getting individual values? Map proposal_details = getDataFromProposalDB(proposalPrefix); @@ -240,8 +242,10 @@ public List getSponsorProjects(Address address){ BigInteger totalSponsorBondICX = BigInteger.ZERO; BigInteger totalSponsorBondbnUSD = BigInteger.ZERO; List> projectDetails = new ArrayList<>(); - for (int i = 0; i < proposalsKeys.size(); i++) { - String _ipfs_key = proposalsKeys.get(i); + ArrayDB proposalKeysArray = sponsorProjects.at(_wallet_address.toString()); + int proposalKeysSize = proposalKeysArray.size(); + for (int i = 0; i < proposalKeysSize; i++) { + String _ipfs_key = proposalKeysArray.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); Map proposal_details = proposalData.getDataFromProposalDB(proposalPrefix); if (!proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { From 439bdc075d2ffe405dfc318cc0881841d2091427 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 22 Nov 2022 15:24:05 +0545 Subject: [PATCH 092/112] fix `is_admin` method for inter-score call method for CPSTreasury --- .../java/community/icon/cps/score/cpstreasury/CPSTreasury.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 3d58e406..b9986534 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -93,7 +93,7 @@ private Boolean proposalExists(String _ipfs_key) { } private void validateAdmins() { - Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "isAdmin", Context.getCaller()); + Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "is_admin", Context.getCaller()); Context.require(isAdmin, TAG + ": Only admins can call this method"); } From 309cef3207c743fcf63b3042bf267af72c28120f Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 22 Nov 2022 15:25:52 +0545 Subject: [PATCH 093/112] Updated - Removed unused variables and methods - remove whitespaces - remove comments form file - optimize variable for multi-used variables - --- .../cps/score/cpstreasury/CPSTreasury.java | 94 +++++++------------ 1 file changed, 36 insertions(+), 58 deletions(-) diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index b9986534..1baa6d14 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -17,32 +17,17 @@ import community.icon.cps.score.cpstreasury.utils.consts; -public class CPSTreasury extends ProposalData implements CPSTreasuryInterface{ +public class CPSTreasury extends ProposalData implements CPSTreasuryInterface { private static final String TAG = "CPS_TREASURY"; private static final String PROPOSAL_DB_PREFIX = "proposal"; private static final String PROPOSALS_KEYS = "_proposals_keys"; private static final String PROPOSALS_KEY_LIST_INDEX = "proposals_key_list_index"; - private static final String FUND_RECORD = "fund_record"; private static final String INSTALLMENT_FUND_RECORD = "installment_fund_record"; - private static final String TOTAL_INSTALLMENT_COUNT = "_total_installment_count"; - private static final String TOTAL_TIMES_INSTALLMENT_PAID = "_total_times_installment_paid"; - private static final String TOTAL_TIMES_REWARD_PAID = "_total_times_reward_paid"; - private static final String TOTAL_INSTALLMENT_PAID = "_total_installment_paid"; - private static final String TOTAL_REWARD_PAID = "_total_reward_paid"; - private static final String INSTALLMENT_AMOUNT = "installment_amount"; - private static final String SPONSOR_BOND_AMOUNT = "sponsor_bond_amount"; private static final String CPS_SCORE = "_cps_score"; private static final String CPF_TREASURY_SCORE = "_cpf_treasury_score"; private static final String BALANCED_DOLLAR = "balanced_dollar"; - private static final String SPONSOR_ADDRESS = "sponsor_address"; - private static final String CONTRIBUTOR_ADDRESS = "contributor_address"; - private static final String STATUS = "status"; - private static final String IPFS_HASH = "ipfs_hash"; - private static final String SPONSOR_REWARD = "sponsor_reward"; - private static final String TOTAL_BUDGET = "total_budget"; - private static final String ACTIVE = "active"; private static final String DISQUALIFIED = "disqualified"; private static final String COMPLETED = "completed"; @@ -51,7 +36,6 @@ public class CPSTreasury extends ProposalData implements CPSTreasuryInterface{ private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); private final DictDB proposalsKeyListIndex = Context.newDictDB(PROPOSALS_KEY_LIST_INDEX, Integer.class); - private final DictDB fundRecord = Context.newDictDB(FUND_RECORD, BigInteger.class); private final BranchDB> installmentFundRecord = Context.newBranchDB(INSTALLMENT_FUND_RECORD, BigInteger.class); private final VarDB
cpfTreasuryScore = Context.newVarDB(CPF_TREASURY_SCORE, Address.class); @@ -76,14 +60,6 @@ public void fallback() { Context.revert(TAG + ": ICX can only be send by CPF Treasury Score"); } - private void setId(String _val) { - id.set(_val); - } - - private String getId() { - return id.get(); - } - private String proposalPrefix(String _proposal_key) { return PROPOSAL_DB_PREFIX + "|" + "|" + _proposal_key; } @@ -118,11 +94,6 @@ private void addRecord(ProposalAttributes _proposal) { proposalsKeyListIndex.set(ipfs_hash, proposalsKeys.size() - 1); } - private Map getProjects(String _proposal_key) { - ProposalData proposalData = new ProposalData(); - return proposalData.getDataFromProposalDB(_proposal_key); - } - @Override @External public void setCpsScore(Address _score) { @@ -131,7 +102,7 @@ public void setCpsScore(Address _score) { } @Override - @External(readonly = true) //Todo java convention in get methods?? + @External(readonly = true) public Address getCpsScore() { return cpsScore.get(); } @@ -173,7 +144,6 @@ public Address getBnUSDScore() { for (int i = 0; i < proposalKeysSize; i++) { String _ipfs_key = proposalKeysArray.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); - // todo: getting entire proposal details or getting individual values? Map proposal_details = getDataFromProposalDB(proposalPrefix); if (!proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { if (proposal_details.get(consts.CONTRIBUTOR_ADDRESS).equals(_wallet_address)) { @@ -215,9 +185,9 @@ public Address getBnUSDScore() { @Override @External(readonly = true) - public List getContributorProjects(Address address){ + public List getContributorProjects(Address address) { List contributorProjects = new ArrayList<>(); - for (int i = 0; i < this.contributorProjects.at(address.toString()).size(); i++){ + for (int i = 0; i < this.contributorProjects.at(address.toString()).size(); i++) { contributorProjects.add(this.contributorProjects.at(address.toString()).get(i)); } return contributorProjects; @@ -225,9 +195,9 @@ public List getContributorProjects(Address address){ @Override @External(readonly = true) - public List getSponsorProjects(Address address){ + public List getSponsorProjects(Address address) { List sponsorProjects = new ArrayList<>(); - for (int i = 0; i < this.sponsorProjects.at(address.toString()).size(); i++){ + for (int i = 0; i < this.sponsorProjects.at(address.toString()).size(); i++) { sponsorProjects.add(this.sponsorProjects.at(address.toString()).get(i)); } return sponsorProjects; @@ -332,7 +302,7 @@ public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, Big public void send_installment_to_contributor(String _ipfs_key) { validateCpsScore(); Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); - BigInteger installmentAmount = BigInteger.ZERO; + BigInteger installmentAmount; String prefix = proposalPrefix(_ipfs_key); Map proposalData = getDataFromProposalDB(prefix); @@ -352,8 +322,9 @@ public void send_installment_to_contributor(String _ipfs_key) { setInstallmentCount(prefix, newInstallmentCount); setRemainingAmount(prefix, remainingAmount.subtract(installmentAmount)); setWithdrawAmount(prefix, withdrawAmount.add(installmentAmount)); - installmentFundRecord.at(contributorAddress.toString()).set(flag, - installmentFundRecord.at(contributorAddress.toString()).getOrDefault(flag, BigInteger.ZERO).add(installmentAmount)); + DictDB installmentFund = this.installmentFundRecord.at(contributorAddress.toString()); + BigInteger installmentFundAmount = installmentFund.getOrDefault(flag, BigInteger.ZERO); + installmentFund.set(flag, installmentFundAmount.add(installmentAmount)); ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); if (newInstallmentCount == 0) { @@ -367,7 +338,7 @@ public void send_reward_to_sponsor(String _ipfs_key) { validateCpsScore(); Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); - BigInteger installmentAmount = BigInteger.ZERO; + BigInteger installmentAmount; String prefix = proposalPrefix(_ipfs_key); int sponsorRewardCount = getSponsorRewardCount(prefix); @@ -386,7 +357,8 @@ public void send_reward_to_sponsor(String _ipfs_key) { setSponsorRewardCount(prefix, newSponsorRewardCount); setSponsorWithdrawAmount(prefix, sponsorWithdrawAmount.add(installmentAmount)); setSponsorRemainingAmount(prefix, sponsorRemainingAmount.subtract(installmentAmount)); - installmentFundRecord.at(sponsorAddress.toString()).set(flag, installmentFundRecord.at(sponsorAddress.toString()).getOrDefault(flag, BigInteger.ZERO).add(installmentAmount)); + DictDB installmentFunds = installmentFundRecord.at(sponsorAddress.toString()); + installmentFunds.set(flag, installmentFunds.getOrDefault(flag, BigInteger.ZERO).add(installmentAmount)); ProposalFundSent(sponsorAddress, "New installment " + installmentAmount + " " + flag + " sent to sponsor address."); } @@ -405,13 +377,13 @@ public void disqualify_project(String _ipfs_key) { BigInteger sponsorWithdrawAmount = getSponsorWithdrawAmount(prefix); String flag = getToken(prefix); - BigInteger remainingBudget = totalBudget.subtract(withdrawAmount); BigInteger remainingReward = sponsorReward.subtract(sponsorWithdrawAmount); BigInteger totalReturnAmount = remainingBudget.add(remainingReward); + Address cpfTreasuryAddres = cpfTreasuryScore.get(); if (flag.equals(consts.ICX)) { - callScore(totalReturnAmount, cpfTreasuryScore.get(), "disqualify_proposal_fund", _ipfs_key); + callScore(totalReturnAmount, cpfTreasuryAddres, "disqualify_proposal_fund", _ipfs_key); } else if (flag.equals(consts.bnUSD)) { JsonObject disqualifyProjectParams = new JsonObject(); disqualifyProjectParams.add("method", "disqualify_project"); @@ -419,7 +391,7 @@ public void disqualify_project(String _ipfs_key) { params.add("ipfs_key", _ipfs_key); disqualifyProjectParams.add("params", params); - callScore(balancedDollar.get(), "transfer", cpfTreasuryScore.get(), totalReturnAmount, disqualifyProjectParams.toString().getBytes()); + callScore(balancedDollar.get(), "transfer", cpfTreasuryAddres, totalReturnAmount, disqualifyProjectParams.toString().getBytes()); } else { Context.revert(TAG + ": Not supported token."); } @@ -430,17 +402,21 @@ public void disqualify_project(String _ipfs_key) { @Override @External public void claim_reward() { - BigInteger availableAmountICX = installmentFundRecord.at(Context.getCaller().toString()).getOrDefault(consts.ICX, BigInteger.ZERO); - BigInteger availableAmountbnUSD = installmentFundRecord.at(Context.getCaller().toString()).getOrDefault(consts.bnUSD, BigInteger.ZERO); + Address caller = Context.getCaller(); + DictDB installmentFundRecord = this.installmentFundRecord.at(caller.toString()); + BigInteger availableAmountICX = installmentFundRecord.getOrDefault(consts.ICX, BigInteger.ZERO); + BigInteger availableAmountbnUSD = installmentFundRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO); if (availableAmountICX.compareTo(BigInteger.ZERO) > 0) { - installmentFundRecord.at(Context.getCaller().toString()).set(consts.ICX, BigInteger.ZERO); - Context.transfer(Context.getCaller(), availableAmountICX); - ProposalFundWithdrawn(Context.getCaller(), availableAmountICX + " " + consts.ICX + " withdrawn to " + Context.getCaller()); + installmentFundRecord.set(consts.ICX, BigInteger.ZERO); + Context.transfer(caller, availableAmountICX); + ProposalFundWithdrawn(caller, availableAmountICX + " " + consts.ICX + + " withdrawn to " + caller); } else if (availableAmountbnUSD.compareTo(BigInteger.ZERO) > 0) { - installmentFundRecord.at(Context.getCaller().toString()).set(consts.bnUSD, BigInteger.ZERO); - callScore(balancedDollar.get(), "transfer", Context.getCaller(), availableAmountbnUSD); + installmentFundRecord.set(consts.bnUSD, BigInteger.ZERO); + callScore(balancedDollar.get(), "transfer", caller, availableAmountbnUSD); } else { - Context.revert(TAG + ": Claim Reward Fails. Available amount(ICX) = " + availableAmountICX + " and Available amount(bnUSD) = " + availableAmountbnUSD); + Context.revert(TAG + ": Claim Reward Fails. Available amount(ICX) = " + availableAmountICX + + " and Available amount(bnUSD) = " + availableAmountbnUSD); } } @@ -451,7 +427,8 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { String unpacked_data = new String(_data); JsonObject jsonObject = Json.parse(unpacked_data).asObject(); JsonObject params = jsonObject.get("params").asObject(); - if (jsonObject.get("method").asString().equals("deposit_proposal_fund")) { + String methodName = jsonObject.get("method").asString(); + if (methodName.equals("deposit_proposal_fund")) { String ipfs_hash = params.get("ipfs_hash").asString(); int project_duration = params.get("project_duration").asInt(); BigInteger total_budget = new BigInteger(params.get("total_budget").asString(), 16); @@ -469,7 +446,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { proposalAttributes.sponsor_address = sponsor_address; proposalAttributes.status = ACTIVE; depositProposalFund(proposalAttributes, _value); - } else if (jsonObject.get("method").asString().equals("budget_adjustment")) { + } else if (methodName.equals("budget_adjustment")) { String ipfs_key = params.get("_ipfs_key").asString(); BigInteger added_budget = new BigInteger(params.get("_added_budget").asString(), 16); BigInteger added_sponsor_reward = new BigInteger(params.get("_added_sponsor_reward").asString(), 16); @@ -477,14 +454,14 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { update_proposal_fund(ipfs_key, added_budget, added_sponsor_reward, added_installment_count); } else { - Context.revert(TAG + jsonObject.get("method").asString() + " Not a valid method."); + Context.revert(TAG + methodName + " Not a valid method."); } } -// for migration into java contract + // for migration into java contract @Override @External - public void updateSponsorAndContributorProjects(){ + public void updateSponsorAndContributorProjects() { validateAdmins(); int startIndex = batchSize.getOrDefault(0); int size = proposalsKeys.size(); @@ -503,7 +480,8 @@ public void updateSponsorAndContributorProjects(){ } } - public T callScore(Class t, Address address, String method, Object... params) { + + public T callScore(Class t, Address address, String method, Object... params) { return Context.call(t, address, method, params); } From 234358b28cab087af4125f42cb4ebd2e482ce9ac Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 25 Nov 2022 20:21:26 +0545 Subject: [PATCH 094/112] added lisbon testnet address --- CPSCore/build.gradle | 2 +- CPSTreasury/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle index 971a1788..af2fab01 100644 --- a/CPSCore/build.gradle +++ b/CPSCore/build.gradle @@ -30,7 +30,7 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 - to = 'cx0355e153f269c05f64100d34d3c48a002b404dc5' + to = 'cx0546dc4c03491a0690b910b505eec537bbf377a5' } local { uri = 'http://localhost:9082/api/v3' diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index 1e0c4dfc..1e595c31 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -28,7 +28,7 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 - to = 'cxda945837404c889bf001546cc6705bd6ac40f077' + to = 'cxabc97ed26cb147eeef55b1728102aea25af8f62f' } local { uri = 'http://localhost:9082/api/v3' From 510c05a3231112101affac4efe087bb6c1569785 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Fri, 25 Nov 2022 20:21:54 +0545 Subject: [PATCH 095/112] added methods for proposal keys migration and changes made to readonly methods --- .../icon/cps/score/cpscore/CPSCore.java | 447 ++++++++++++------ .../cps/score/cpscore/utils/Constants.java | 4 + .../cps/score/cpstreasury/CPSTreasury.java | 19 + 3 files changed, 320 insertions(+), 150 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 378163f8..99998fd8 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -13,7 +13,9 @@ import scorex.util.HashMap; import java.math.BigInteger; + import scorex.util.ArrayList; + import java.util.List; import java.util.Map; @@ -22,6 +24,7 @@ import static community.icon.cps.score.cpscore.utils.Constants.*; import static community.icon.cps.score.cpscore.utils.Checkers.*; import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; + import community.icon.cps.score.lib.interfaces.CPSCoreInterface; import community.icon.cps.score.cpscore.utils.Migration; @@ -70,6 +73,9 @@ public class CPSCore implements CPSCoreInterface { private final VarDB swapCount = Context.newVarDB(SWAP_COUNT, Integer.class); private final DictDB proposalRank = Context.newDictDB(PROPOSAL_RANK, Integer.class); private final ArrayDB
priorityVotedPreps = Context.newArrayDB(PRIORITY_VOTED_PREPS, Address.class); + private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS, String.class); + private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS, String.class); + private final VarDB batchSize = Context.newVarDB(BATCH_SIZE, Integer.class); public CPSCore() { PeriodController periodController = new PeriodController(); @@ -106,7 +112,7 @@ public void set_cps_treasury_score(Address _score) { @Override @External - public void setCpsTreasuryScore(Address score){ + public void setCpsTreasuryScore(Address score) { validateAdminScore(score); SetterGetter setterGetter = new SetterGetter(); setterGetter.cpsTreasuryScore.set(score); @@ -121,7 +127,7 @@ public Address get_cps_treasury_score() { @Override @External(readonly = true) - public Address getCpsTreasuryScore(){ + public Address getCpsTreasuryScore() { SetterGetter setterGetter = new SetterGetter(); return setterGetter.cpsTreasuryScore.get(); } @@ -150,13 +156,12 @@ public Address get_cpf_treasury_score() { @Override @External(readonly = true) - public Address getCpfTreasuryScore(){ + public Address getCpfTreasuryScore() { SetterGetter setterGetter = new SetterGetter(); return setterGetter.cpfScore.get(); } - @External public void setBnusdScore(Address score) { validateAdminScore(score); @@ -259,7 +264,7 @@ private void burn(BigInteger amount, @Optional Address token) { @Override @External(readonly = true) - public int getPeriodCount(){ + public int getPeriodCount() { PeriodController periodController = new PeriodController(); return periodController.periodCount.get(); } @@ -351,7 +356,7 @@ private List> getPrepTerm() { return (List>) prepDict.get("preps"); } - private Map getPRepInfo(Address address){ + private Map getPRepInfo(Address address) { return callScore(Map.class, SYSTEM_ADDRESS, "getPRep", address); } @@ -373,7 +378,7 @@ private BigInteger getStake(Address address) { return (BigInteger) getPRepInfo(address).get("power"); } - private void setPreps() { + private void setPreps() { PReps pReps = new PReps(); ArrayDBUtils.clearArrayDb(pReps.validPreps); List
prepsList = getPrepsAddress(); @@ -389,16 +394,18 @@ private void setPreps() { } - private void removeSponsor(Address address) { + private void removeSponsor(Address address, String ipfsHash) { Context.require(ArrayDBUtils.containsInArrayDb(address, sponsors), address + " not on sponsor list."); ArrayDBUtils.removeArrayItem(sponsors, address); + ArrayDBUtils.removeArrayItem(sponsorProjects.at(address), ipfsHash); } - private void removeContributor(Address address) { + private void removeContributor(Address address, String ipfsHash) { Context.require(ArrayDBUtils.containsInArrayDb(address, contributors), address + " not on contributor list."); ArrayDBUtils.removeArrayItem(contributors, address); + ArrayDBUtils.removeArrayItem(contributorProjects.at(address), ipfsHash); } @External(readonly = true) @@ -444,7 +451,7 @@ public boolean checkPriorityVoting(Address prep) { @External(readonly = true) public List sortPriorityProposals() { String[] pendingProposals = new String[pending.size()]; - for (int i = 0; i < pending.size(); i++){ + for (int i = 0; i < pending.size(); i++) { pendingProposals[i] = pending.get(i); } mergeSort(pendingProposals, 0, pending.size() - 1, getPriorityVoteResult()); @@ -503,7 +510,7 @@ public void setPrepPenaltyAmount(BigInteger[] penalty) { @Override @Deprecated(since = "JAVA translation", forRemoval = true) @External - public void set_prep_penalty_amount(BigInteger[] _penalty){ + public void set_prep_penalty_amount(BigInteger[] _penalty) { setPrepPenaltyAmount(_penalty); } @@ -538,14 +545,12 @@ public Map loginPrep(Address address) { loginData.put("payPenalty", BigInteger.ZERO); loginData.put("votingPRep", BigInteger.ZERO); - } - else if (ArrayDBUtils.containsInArrayDb(address, pReps.denylist)) { + } else if (ArrayDBUtils.containsInArrayDb(address, pReps.denylist)) { loginData.put("isRegistered", BigInteger.ZERO); loginData.put("payPenalty", BigInteger.ONE); loginData.put("votingPRep", BigInteger.ZERO); loginData.put("penaltyAmount", getPenaltyAmount(address)); - } - else if (ArrayDBUtils.containsInArrayDb(address, pReps.registeredPreps)) { + } else if (ArrayDBUtils.containsInArrayDb(address, pReps.registeredPreps)) { loginData.put("isRegistered", BigInteger.ONE); loginData.put("payPenalty", BigInteger.ZERO); loginData.put("votingPRep", BigInteger.ZERO); @@ -735,7 +740,6 @@ public void submitProposal(ProposalAttributes proposals) { String tokenFlag = proposals.token; Context.require(tokenFlag.equals(bnUSD), TAG + ": " + tokenFlag + " Not a supported token."); - ProposalAttributes proposalAttributes = new ProposalAttributes(); String ipfsHash = proposals.ipfs_hash; String ipfsHashPrefix = proposalPrefix(ipfsHash); @@ -744,6 +748,7 @@ public void submitProposal(ProposalAttributes proposals) { proposalsKeyListIndex.set(ipfsHash, proposalsKeyList.size() - 1); sponsorPending.add(ipfsHash); contributors.add(Context.getCaller()); + contributorProjects.at(Context.getCaller()).add(ipfsHash); ProposalSubmitted(Context.getCaller(), "Successfully submitted a Proposal."); BigInteger totalFund = proposalFees.getOrDefault(BigInteger.ZERO); @@ -818,8 +823,7 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option } else if (voteIndex == REJECT_) { ArrayDBUtils.removeArrayItem(ProposalDataDb.rejectVoters.at(proposalPrefix), caller); ProposalDataDb.rejectedVotes.at(proposalPrefix).set(rejectedVotes.subtract(voterStake)); - } - else{ + } else { ArrayDBUtils.removeArrayItem(abstainVoters.at(proposalPrefix), caller); ProposalDataDb.abstainedVotes.at(proposalPrefix).set(abstainedVotes.subtract(voterStake)); } @@ -854,7 +858,7 @@ public void vote_proposal(String _ipfs_key, String _vote, String _vote_reason, @ } @External - public void migrateAbstainVotes(Migration[] migrations){ + public void migrateAbstainVotes(Migration[] migrations) { validateAdmins(); Context.require(migrations.length <= MIGRATION_BATCH, TAG + ": The length of data should be " + "smaller than or equal to " + MIGRATION_BATCH); @@ -1085,10 +1089,10 @@ public List get_proposals_keys_by_status(String _status) { public int checkChangeVote(Address address, String ipfsHash, String proposalType) { if (proposalType.equals(PROPOSAL)) { String proposalPrefix = proposalPrefix(ipfsHash); - return ProposalDataDb.votersListIndex.at(proposalPrefix).at(address).get(CHANGE_VOTE); + return ProposalDataDb.votersListIndex.at(proposalPrefix).at(address).getOrDefault(CHANGE_VOTE, 0); } else if (proposalType.equals(PROGRESS_REPORTS)) { String progressReportPrefix = progressReportPrefix(ipfsHash); - return votersListIndices.at(progressReportPrefix).at(address).get(CHANGE_VOTE); + return votersListIndices.at(progressReportPrefix).at(address).getOrDefault(CHANGE_VOTE, 0); } else { return 0; } @@ -1122,15 +1126,15 @@ public Map>> getProjectAmounts() { List proposalsKeysByStatus = this.get_proposals_keys_by_status(statusList.get(statusId)); for (String proposalKey : proposalsKeysByStatus) { - Map proposalDetails = getProposalDetails(proposalKey); - BigInteger projectBudget = (BigInteger) proposalDetails.get(TOTAL_BUDGET); - if (proposalDetails.get(TOKEN).equals(ICX)) { + String proposalPrefix = proposalPrefix(proposalKey); + BigInteger projectBudget = ProposalDataDb.totalBudget.at(proposalPrefix).getOrDefault(BigInteger.ZERO); + String token = ProposalDataDb.token.at(proposalPrefix).getOrDefault(""); + if (token.equals(ICX)) { amountICX = amountICX.add(projectBudget); } else { amountBnusd = amountBnusd.add(projectBudget); } } - if (statusId == 0) { pendingAmountIcx = amountICX; pendingAmountBnusd = amountBnusd; @@ -1171,24 +1175,28 @@ public Map getSponsorsRecord() { List proposalKeys = new ArrayList<>(); Map sponsorsDict = new HashMap<>(); - List activeProposals = get_proposals_keys_by_status(ACTIVE); - proposalKeys.addAll(activeProposals); - List pausedProposals = get_proposals_keys_by_status(PAUSED); - proposalKeys.addAll(pausedProposals); - List completedProposals = get_proposals_keys_by_status(COMPLETED); - proposalKeys.addAll(completedProposals); - - for (String proposal : proposalKeys) { - Map proposalDetails = getProposalDetails(proposal); - String sponsorAddress = proposalDetails.get(SPONSOR_ADDRESS).toString(); - int sponsorValue = 0; - try{ - sponsorValue = sponsorsDict.get(sponsorAddress); - } catch (Exception e){ - sponsorsDict.put(sponsorAddress, 0); - } - - sponsorsDict.put(sponsorAddress, sponsorValue + 1); +// List activeProposals = get_proposals_keys_by_status(ACTIVE); +// proposalKeys.addAll(activeProposals); +// List pausedProposals = get_proposals_keys_by_status(PAUSED); +// proposalKeys.addAll(pausedProposals); +// List completedProposals = get_proposals_keys_by_status(COMPLETED); +// proposalKeys.addAll(completedProposals); +// +// for (String proposal : proposalKeys) { +// String proposalPrefix = proposalPrefix(proposal); +// String sponsorAddress = ProposalDataDb.sponsorAddress.at(proposalPrefix).get().toString(); +// int sponsorValue = 0; +// try { +// sponsorValue = sponsorsDict.get(sponsorAddress); +// } catch (Exception e) { +// sponsorsDict.put(sponsorAddress, 0); +// } +// +// sponsorsDict.put(sponsorAddress, sponsorValue + 1); +// } + for (int i = 0; i < sponsors.size(); i++){ + Address sponsorAddress = sponsors.get(i); + sponsorsDict.put(sponsorAddress.toString(), sponsorProjects.at(sponsorAddress).size()); } return sponsorsDict; } @@ -1373,8 +1381,8 @@ private void updateProgressReportResult() { updateProposalStatus(_ipfs_hash, DISQUALIFIED); callScore(getCpsTreasuryScore(), "disqualify_project", _ipfs_hash); - removeContributor(_contributor_address); - removeSponsor(_sponsor_address); + removeContributor(_contributor_address, _ipfs_hash); + removeSponsor(_sponsor_address, _ipfs_hash); sponsorDepositStatus.at(proposal_prefix).set(BOND_CANCELLED); @@ -1408,8 +1416,8 @@ private void checkProgressReportSubmission() { callScore(getCpsTreasuryScore(), "disqualify_project", _ipfs_hash); - removeContributor(_contributor_address); - removeSponsor(_sponsor_address); + removeContributor(_contributor_address, _ipfs_hash); + removeSponsor(_sponsor_address, _ipfs_hash); sponsorDepositStatus.at(proposalPrefix).set(BOND_CANCELLED); BigInteger _sponsor_deposit_amount = (BigInteger) _proposal_details.get(SPONSOR_DEPOSIT_AMOUNT); @@ -1437,10 +1445,10 @@ private void updateBudgetAdjustments(String _budget_key) { BigInteger _approved_votes = (BigInteger) _vote_result.get(APPROVED_VOTES); BigInteger _total_votes = (BigInteger) _vote_result.get(TOTAL_VOTES); PReps pReps = new PReps(); - double votersRatio = (double) _approve_voters/_total_voters; + double votersRatio = (double) _approve_voters / _total_voters; if (_total_voters == 0 || _total_votes.equals(BigInteger.ZERO) || pReps.validPreps.size() < MINIMUM_PREPS) { budgetAdjustmentStatus.at(_prefix).set(REJECTED); - } else if (votersRatio >= MAJORITY && (_approved_votes.doubleValue()/_total_votes.doubleValue()) >= MAJORITY) { + } else if (votersRatio >= MAJORITY && (_approved_votes.doubleValue() / _total_votes.doubleValue()) >= MAJORITY) { String _ipfs_hash = (String) _report_result.get(IPFS_HASH); String proposal_prefix = proposalPrefix(_ipfs_hash); String token_flag = token.at(proposal_prefix).getOrDefault(""); @@ -1485,8 +1493,8 @@ private void updateProposalsResult() { checkInactivePreps(ProposalDataDb.votersList.at(proposalPrefix)); double voters_ratio = 0; - if (totalVoters != 0){ - voters_ratio = (double) approvedVoters/totalVoters; + if (totalVoters != 0) { + voters_ratio = (double) approvedVoters / totalVoters; } if (totalVoters == 0 || totalVotes.equals(BigInteger.ZERO) || pReps.validPreps.size() < MINIMUM_PREPS) { updateProposalStatus(proposal, REJECTED); @@ -1498,6 +1506,7 @@ private void updateProposalsResult() { updateProposalStatus(proposal, ACTIVE); updatedStatus = ACTIVE; sponsors.add(sponsorAddress); + sponsorProjects.at(sponsorAddress).add(proposal); ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).set(BOND_APPROVED); callScore(get_cpf_treasury_score(), "transfer_proposal_fund_to_cps_treasury", proposal, projectDuration, sponsorAddress, contributorAddress, flag, totalBudget); @@ -1531,9 +1540,9 @@ private void updateProposalsResult() { proposalRank.set(proposal, null); if (updatedStatus.equals(REJECTED)) { - removeContributor(contributorAddress); - sponsorDepositStatus.at(proposal).set(BOND_RETURNED); - BigInteger halfSubmissionFee = BigInteger.valueOf(APPLICATION_FEE /2).multiply(EXA); + removeContributor(contributorAddress, proposal); + sponsorDepositStatus.at(proposalPrefix).set(BOND_RETURNED); + BigInteger halfSubmissionFee = BigInteger.valueOf(APPLICATION_FEE / 2).multiply(EXA); Context.transfer(contributorAddress, halfSubmissionFee); proposalFees.set(proposalFees.get().subtract(halfSubmissionFee)); @@ -1572,9 +1581,9 @@ private void updateProgressReportStatus(String progressHash, String progressStat private void checkInactivePreps(ArrayDB
prepList) { PReps pReps = new PReps(); - for(int i = 0; i < pReps.validPreps.size(); i++){ + for (int i = 0; i < pReps.validPreps.size(); i++) { Address prep = pReps.validPreps.get(i); - if (!containsInArrayDb(prep, prepList) && !containsInArrayDb(prep, pReps.inactivePreps)){ + if (!containsInArrayDb(prep, prepList) && !containsInArrayDb(prep, pReps.inactivePreps)) { pReps.inactivePreps.add(prep); } } @@ -1585,7 +1594,7 @@ private Map getProposalDetails(String proposal) { return getDataFromProposalDB(proposalPrefix(proposal)); } - private void addNewProgressReportKey(String ipfsHash, String reportHash){ + private void addNewProgressReportKey(String ipfsHash, String reportHash) { String prefix = proposalPrefix(ipfsHash); if (!containsInArrayDb(reportHash, progressReports.at(prefix))) { progressReports.at(prefix).add(reportHash); @@ -1595,7 +1604,7 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash){ @External(readonly = true) public Map getProposalDetails(String status, @Optional Address walletAddress, @Optional int startIndex, @Optional int endIndex) { if (endIndex == 0) { - endIndex = 20; + endIndex = 10; } if (!STATUS_TYPE.contains(status)) { return Map.of(MESSAGE, "Not a valid _status."); @@ -1606,12 +1615,12 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash){ if (startIndex < 0) { startIndex = 0; } - if ((endIndex - startIndex) > 50) { + if ((endIndex - startIndex) > 10) { return Map.of(MESSAGE, "Page length must not be greater than 50."); } int count = proposalKeys.size(); - if (endIndex > count){ + if (endIndex > count) { endIndex = count; } // endIndex = ((endIndex > count) ? endIndex : count); @@ -1628,7 +1637,6 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash){ } } else if (propStatus.equals(status)) { proposalsList.add(proposalDetails); - } } @@ -1662,7 +1670,7 @@ private Map getProgressReportDetails(String progressKey) { @External(readonly = true) public Map getProgressReports(String status, @Optional int startIndex, @Optional int endIndex) { if (endIndex == 0) { - endIndex = 20; + endIndex = 10; } if (!PROGRESS_REPORT_STATUS_TYPE.contains(status)) { return Map.of(MESSAGE, "Not a valid _status."); @@ -1674,12 +1682,12 @@ private Map getProgressReportDetails(String progressKey) { if (startIndex < 0) { startIndex = 0; } - if ((endIndex - startIndex) > 50) { + if ((endIndex - startIndex) > 10) { return Map.of(MESSAGE, "Page length must not be greater than 50."); } int count = progressReportKeys.size(); - if (endIndex > count){ + if (endIndex > count) { endIndex = count; } @@ -1715,9 +1723,7 @@ public Map getProgressReportsByHash(String reportKey) { return Map.of("message", TAG + ": Not a valid IPFS Hash for Progress Report"); } - Map progressDetails = getProgressReportDetails(reportKey); - String _ipfs_hash = (String) progressDetails.get(IPFS_HASH); - return progressDetails; + return getProgressReportDetails(reportKey); } @Override @@ -1730,9 +1736,6 @@ public Map get_progress_reports_by_hash(String _report_key) { @External(readonly = true) public Map getProgressReportsByProposal(String ipfsKey) { String proposalPrefix = proposalPrefix(ipfsKey); - Map proposalDetails = getProposalDetails(ipfsKey); - String projectTitle = (String) proposalDetails.get(PROJECT_TITLE); - String contributorAddress = proposalDetails.get(CONTRIBUTOR_ADDRESS).toString(); ArrayDB reportKeys = ProposalDataDb.progressReports.at(proposalPrefix); List> progressReportList = new ArrayList<>(); @@ -1784,7 +1787,7 @@ public Map getSponsorsRequests(String status, Address sponsorAdd return Map.of(MESSAGE, "Page length must not be greater than 50."); } int count = proposalKeys.size(); - if (endIndex > count){ + if (endIndex > count) { endIndex = count; } @@ -1792,11 +1795,12 @@ public Map getSponsorsRequests(String status, Address sponsorAdd for (int i = startIndex; i < endIndex; i++) { String proposalKey = (String) proposalKeys.get(i); - Map proposalDetails = getProposalDetails(proposalKey); - Address proposalSponsor = (Address) proposalDetails.get(SPONSOR_ADDRESS); + String proposalPrefix = proposalPrefix(proposalKey); + Address proposalSponsor = ProposalDataDb.sponsorAddress.at(proposalPrefix).get(); if (proposalSponsor.equals(sponsorAddress)) { - String sponsorDepositStatus = (String) proposalDetails.get(SPONSOR_DEPOSIT_STATUS); + String sponsorDepositStatus = ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).getOrDefault(""); if (sponsorDepositStatus.equals(BOND_APPROVED)) { + Map proposalDetails = getProposalDetails(proposalKey); String token = (String) proposalDetails.get(TOKEN); BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); if (token.equals(ICX)) { @@ -1820,20 +1824,19 @@ public Map get_sponsors_requests(String _status, Address _sponso } /*** - Returns remaining projects and progress reports to vote on the current voting period - :param _project_type: "proposal" or "progress_report" which type, remaining votes need to be checked - :type _project_type: str - :param _wallet_address: Wallet Address of the P-Rep - :type _wallet_address: str - :return: list of details of proposal or progress report what they need to vote on the same voting period - ***/ + Returns remaining projects and progress reports to vote on the current voting period + :param _project_type: "proposal" or "progress_report" which type, remaining votes need to be checked + :type _project_type: str + :param _wallet_address: Wallet Address of the P-Rep + :type _wallet_address: str + :return: list of details of proposal or progress report what they need to vote on the same voting period + ***/ @External(readonly = true) public List> get_remaining_project(String _project_type, Address _wallet_address) { List> _remaining_proposals = new ArrayList<>(); List> _remaining_progress_report = new ArrayList<>(); if (_project_type.equals(PROPOSAL)) { List _proposal_keys = get_proposals_keys_by_status(PENDING); - for (String _ipfs_key : _proposal_keys) { String prefix = proposalPrefix(_ipfs_key); @@ -1855,40 +1858,34 @@ public List> get_remaining_project(String _project_type, Add _remaining_progress_report.add(progressReportDetails); } } - return _remaining_progress_report; } return List.of(Map.of("", "")); } - /*** - Get vote results by proposal - :param _ipfs_key : proposal ipfs key - :type _ipfs_key : str - :return: Vote status of given _ipfs_key - :rtype : dict - ***/ + /*** + Get vote results by proposal + :param _ipfs_key : proposal ipfs key + :type _ipfs_key : str + :return: Vote status of given _ipfs_key + :rtype : dict + ***/ @External(readonly = true) - public Map getVoteResult(String ipfsKey){ - Map _proposal_details = getProposalDetails(ipfsKey); + public Map getVoteResult(String ipfsKey) { String prefix = proposalPrefix(ipfsKey); ArrayDB
_voters_list = ProposalDataDb.votersList.at(prefix); - ArrayDB
_approved_voters_list = ProposalDataDb.approveVoters.at(prefix); - ArrayDB
_rejected_voters_list = ProposalDataDb.rejectVoters.at(prefix); List> _vote_status = new ArrayList<>(); String vote; for (int i = 0; i < _voters_list.size(); i++) { Address voter = _voters_list.get(i); - if (containsInArrayDb(voter, _approved_voters_list)) { + if ((int) votersListIndex.at(prefix).at(voter).getOrDefault(VOTE, NOT_VOTED) == APPROVE_) { vote = APPROVE; - } - else if (containsInArrayDb(voter, _rejected_voters_list)) { + } else if ((int) votersListIndex.at(prefix).at(voter).getOrDefault(VOTE, NOT_VOTED) == REJECT_) { vote = REJECT; - } - else { + } else { vote = ABSTAIN; } String reason = ProposalDataDb.votersReasons.at(prefix).get(i); @@ -1900,30 +1897,30 @@ PREP_NAME, getPrepName(voter), _vote_status.add(_voters); } - return Map.of(DATA, _vote_status, APPROVE_VOTERS, _proposal_details.get(APPROVE_VOTERS), - REJECT_VOTERS, _proposal_details.get(REJECT_VOTERS), - TOTAL_VOTERS, _proposal_details.get(TOTAL_VOTERS), - APPROVED_VOTES, _proposal_details.get(APPROVED_VOTES), - REJECTED_VOTES, _proposal_details.get(REJECTED_VOTES), - TOTAL_VOTES, _proposal_details.get(TOTAL_VOTES)); + return Map.of(DATA, _vote_status, APPROVE_VOTERS, ProposalDataDb.approveVoters.at(prefix).size(), + REJECT_VOTERS, ProposalDataDb.rejectVoters.at(prefix).size(), + TOTAL_VOTERS, ProposalDataDb.totalVoters.at(prefix).getOrDefault(0), + APPROVED_VOTES, ProposalDataDb.approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO), + REJECTED_VOTES, ProposalDataDb.rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO), + TOTAL_VOTES, ProposalDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)); } @Override @External(readonly = true) @Deprecated(since = "JAVA translation", forRemoval = true) - public Map get_vote_result(String _ipfs_key){ + public Map get_vote_result(String _ipfs_key) { return getVoteResult(_ipfs_key); } /*** - Get vote results by progress report - :param reportKey : progress report ipfs key - :type reportKey : str - :return: Vote status of given reportKey - :rtype : dict - ***/ - @External(readonly = true) - public Map getProgressReportResult(String reportKey){ + Get vote results by progress report + :param reportKey : progress report ipfs key + :type reportKey : str + :return: Vote status of given reportKey + :rtype : dict + ***/ + @External(readonly = true) + public Map getProgressReportResult(String reportKey) { Map _proposal_details = getProgressReportDetails(reportKey); String prefix = progressReportPrefix(reportKey); @@ -1936,13 +1933,11 @@ public Map getProgressReportResult(String reportKey){ // Differentiating the P-Rep(s) votes according to their votes for (int i = 0; i < _voters_list.size(); i++) { Address voter = _voters_list.get(i); - if (containsInList(voter, _approved_voters_list)){ + if (containsInList(voter, _approved_voters_list)) { vote = APPROVE; - } - else if(containsInList(voter, _rejected_voters_list)){ + } else if (containsInList(voter, _rejected_voters_list)) { vote = REJECT; - } - else{ + } else { vote = "not voted"; } String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); @@ -1955,7 +1950,7 @@ PREP_NAME, getPrepName(voter), } return Map.of(DATA, _vote_status, APPROVE_VOTERS, _approved_voters_list.size(), - REJECT_VOTERS,_rejected_voters_list.size(), + REJECT_VOTERS, _rejected_voters_list.size(), TOTAL_VOTERS, _proposal_details.get(TOTAL_VOTERS), APPROVED_VOTES, _proposal_details.get(APPROVED_VOTES), REJECTED_VOTES, _proposal_details.get(REJECTED_VOTES), @@ -1965,20 +1960,20 @@ PREP_NAME, getPrepName(voter), @Override @External(readonly = true) @Deprecated(since = "JAVA translation", forRemoval = true) - public Map get_progress_report_result(String _report_key){ + public Map get_progress_report_result(String _report_key) { return getProgressReportResult(_report_key); } - /*** - Get budget adjustment vote results - :param _report_key : progress report ipfs key - :type _report_key : str - :return: Vote status of given _report_key - :rtype : dict - ***/ + /*** + Get budget adjustment vote results + :param _report_key : progress report ipfs key + :type _report_key : str + :return: Vote status of given _report_key + :rtype : dict + ***/ @External(readonly = true) - public Map getBudgetAdjustmentVoteResult(String reportKey){ + public Map getBudgetAdjustmentVoteResult(String reportKey) { Map _proposal_details = getProgressReportDetails(reportKey); String prefix = progressReportPrefix(reportKey); @@ -1991,11 +1986,9 @@ public Map getBudgetAdjustmentVoteResult(String reportKey){ Address voter = _voters_list.get(i); if (containsInList(voter, _approved_voters_list)) { vote = APPROVE; - } - else if (containsInList(voter, _rejected_voters_list)) { + } else if (containsInList(voter, _rejected_voters_list)) { vote = REJECT; - } - else { + } else { vote = "not voted"; } String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); @@ -2018,7 +2011,7 @@ PREP_NAME, getPrepName(voter), @Override @External(readonly = true) @Deprecated(since = "JAVA translation", forRemoval = true) - public Map get_budget_adjustment_vote_result(String _report_key){ + public Map get_budget_adjustment_vote_result(String _report_key) { return getBudgetAdjustmentVoteResult(_report_key); } @@ -2163,7 +2156,7 @@ private void sponsorVote(String ipfsKey, String vote, String voteReason, Address SponsorBondReceived(from, "Sponsor Bond " + value + " " + token + " Received."); } else { - removeContributor(contributorAddress); + removeContributor(contributorAddress, ipfsKey); updateProposalStatus(ipfsKey, REJECTED); BigInteger halfSubmissionFee = BigInteger.valueOf(APPLICATION_FEE / 2).multiply(EXA); Context.transfer(contributorAddress, halfSubmissionFee); @@ -2246,7 +2239,7 @@ public void set_swap_count(int value) { } @External(readonly = true) - public int getSwapCount(){ + public int getSwapCount() { return swapCount.get(); } @@ -2306,26 +2299,24 @@ public List> get_active_proposals() { } /*** - Returns a dict of proposals of provided status - :param walletAddress : user Signing in - :type walletAddress : "iconservice.base.address" - :return: List of all proposals_details - ***/ - @External(readonly =true) + Returns a dict of proposals of provided status + :param walletAddress : user Signing in + :type walletAddress : "iconservice.base.address" + :return: List of all proposals_details + ***/ + @External(readonly = true) public Map getProposalDetailByWallet(Address walletAddress) { List> _proposals_list = new ArrayList<>(); - - for (int i = 0; i < proposalsKeyList.size(); i++) { - Map _proposal_details = getProposalDetails(proposalsKeyList.get(i)); - if (_proposal_details.get(CONTRIBUTOR_ADDRESS).equals(walletAddress)) { - _proposals_list.add(_proposal_details); - } + ArrayDB projects = contributorProjects.at(walletAddress); + for (int i = 0; i < projects.size(); i++) { + Map _proposal_details = getProposalDetails(projects.get(i)); + _proposals_list.add(_proposal_details); } return Map.of(DATA, _proposals_list, COUNT, _proposals_list.size()); } @Override - @External(readonly =true) + @External(readonly = true) public Map get_proposal_detail_by_wallet(Address _wallet_address) { return getProposalDetailByWallet(_wallet_address); } @@ -2424,7 +2415,163 @@ public void callScore(BigInteger amount, Address address, String method, Object. Context.call(amount, address, method, params); } - private void logger(String msg){ + private void logger(String msg) { Context.println(msg); } + + + //***************************************************************************************************************** + /* + to be removed in production, for testing only + */ + //***************************************************************************************************************** + @External + public void add_proposals(ProposalAttributes proposals) { + String proposalPrefix = proposalPrefix(proposals.ipfs_hash); + if (proposalsKeyListIndex.getOrDefault(proposals.ipfs_hash, 0) == 0) { + proposalsKeyList.add(proposals.ipfs_hash); + proposalsKeyListIndex.set(proposals.ipfs_hash, proposalsKeyList.size()); + contributors.add(Context.getCaller()); +// contributorProjects.at(Context.getCaller()).add(proposals.ipfs_hash); + addDataToProposalDB(proposals, proposalPrefix); + } + } + + @External + public void changeStatus(String proposalKey, String status) { + Context.require(ArrayDBUtils.containsInList(status, STATUS_TYPE)); + ProposalDataDb.status.at(proposalPrefix(proposalKey)).set(status); + proposalStatus.get(status).add(proposalKey); + sponsorDepositStatus.at(proposalPrefix(proposalKey)).set(BOND_APPROVED); + if(!status.equals(PENDING)){ +// sponsorProjects.at(sponsorAddress.at(proposalPrefix(proposalKey)).get()).add(proposalKey); + sponsors.add(sponsorAddress.at(proposalPrefix(proposalKey)).get()); + } + } + + @External + public void changeVoteData(String proposalKey, Address address, String vote) { + String prefix = proposalPrefix(proposalKey); + ProposalDataDb.totalVoters.at(prefix).set(12); + ProposalDataDb.totalVotes.at(prefix).set(BigInteger.valueOf(12000)); + ProposalDataDb.votersList.at(prefix).add(address); + votersListIndex.at(prefix).at(address).set(INDEX, ProposalDataDb.votersList.at(prefix).size()); + if (vote.equals(APPROVE)) { + ProposalDataDb.approvedVotes.at(prefix).set(ProposalDataDb.approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO).add(BigInteger.valueOf(1000))); + ProposalDataDb.approveVoters.at(prefix).add(address); + votersListIndex.at(prefix).at(address).set(VOTE, APPROVE_); + } else if (vote.equals(REJECT)) { + ProposalDataDb.rejectedVotes.at(prefix).set(ProposalDataDb.rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO).add(BigInteger.valueOf(1000))); + ProposalDataDb.rejectVoters.at(prefix).add(address); + votersListIndex.at(prefix).at(address).set(VOTE, REJECT_); + } else { + abstainedVotes.at(prefix).set(abstainedVotes.at(prefix).getOrDefault(BigInteger.ZERO).add(BigInteger.valueOf(1000))); + abstainVoters.at(prefix).add(address); + votersListIndex.at(prefix).at(address).set(VOTE, ABSTAIN_); + } + } + + @External(readonly = true) + public Map getSponsorsReqInterScoreCall(String status, Address sponsorAddress, @Optional int startIndex, @Optional int endIndex) { + if (endIndex == 0) { + endIndex = 20; + } + if (!List.of(APPROVED, SPONSOR_PENDING, REJECTED, DISQUALIFIED).contains(status)) { + return Map.of(MESSAGE, "Not a valid _status."); + } + List proposalKeys = new ArrayList<>(); + List sponsorRequests = new ArrayList<>(); + + + if (status.equals(APPROVED)) { + proposalKeys = arrayDBtoList(this.sponsorProjects.at(sponsorAddress)); + List pendingProposals = get_proposals_keys_by_status(PENDING); + String prefix = ""; + String ipfsKey = ""; + for (int i = 0; i < pendingProposals.size(); i++) { + ipfsKey = pendingProposals.get(i); + prefix = proposalPrefix(ipfsKey); + if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { + proposalKeys.add(ipfsKey); + } + } + } else { + List pendingProposals = get_proposals_keys_by_status(status); + String prefix = ""; + String ipfsKey = ""; + for (int i = 0; i < pendingProposals.size(); i++) { + ipfsKey = pendingProposals.get(i); + prefix = proposalPrefix(ipfsKey); + if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { + proposalKeys.add(ipfsKey); + } + } + } + if (startIndex < 0) { + startIndex = 0; + } + if ((endIndex - startIndex) > 50) { + return Map.of(MESSAGE, "Page length must not be greater than 50."); + } + int count = proposalKeys.size(); + if (endIndex > count) { + endIndex = count; + } + + BigInteger sponsorAmountICX = BigInteger.ZERO, sponsorAmountBnusd = BigInteger.ZERO; + + for (int i = startIndex; i < endIndex; i++) { + String proposalKey = (String) proposalKeys.get(i); + String proposalPrefix = proposalPrefix(proposalKey); + String sponsorDepositStatus = ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).getOrDefault(""); + if (sponsorDepositStatus.equals(BOND_APPROVED)) { + Map proposalDetails = getProposalDetails(proposalKey); + String token = (String) proposalDetails.get(TOKEN); + BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); + if (token.equals(ICX)) { + sponsorAmountICX = sponsorAmountICX.add(sponsorDepositAmount); + } else if (token.equals(bnUSD)) { + sponsorAmountBnusd = sponsorAmountBnusd.add(sponsorDepositAmount); + } + sponsorRequests.add(proposalDetails); + } + } + + return Map.of(DATA, sponsorRequests, COUNT, sponsorRequests.size(), + SPONSOR_DEPOSIT_AMOUNT, Map.of(ICX, sponsorAmountICX, bnUSD, sponsorAmountBnusd)); + } + + @External(readonly = true) + public String returnString() { + return ""; + } + + @External(readonly = true) + public String returnStringCon() { + SetterGetter setterGetter = new SetterGetter(); + return callScore(String.class, setterGetter.cpsTreasuryScore.get(), "returnString"); + } + + @External + public void migrateProposals() { + validateAdmins(); + int startIndex = batchSize.getOrDefault(0); + int size = proposalsKeyList.size(); + int endIndex = startIndex + 10; + if (endIndex > size) { + endIndex = size; + } + for (int i = startIndex; i < endIndex; i++) { + String proposalKey = proposalsKeyList.get(i); + String prefix = proposalPrefix(proposalKey); + Address sponsorAddress = ProposalDataDb.sponsorAddress.at(prefix).get(); + Address contributorAddress = ProposalDataDb.contributorAddress.at(prefix).get(); + String proposalStatus = ProposalDataDb.status.at(prefix).get(); + if (!List.of(SPONSOR_PENDING, REJECTED, DISQUALIFIED, PENDING).contains(proposalStatus)) { + sponsorProjects.at(sponsorAddress).add(proposalKey); + } + contributorProjects.at(contributorAddress).add(proposalKey); + } + batchSize.set(endIndex); + } } \ No newline at end of file diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java index eec154b0..bbfb63fc 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java @@ -142,6 +142,8 @@ public class Constants { public static final String PROPOSAL_RANK = "proposal_rank"; public static final String PRIORITY_VOTED_PREPS = "priority_voted_preps"; + public static final String SPONSOR_PROJECTS = "sponsor_projects"; + public static final String CONTRIBUTOR_PROJECTS = "sponsor_projects"; // VOTE KEYS @@ -188,4 +190,6 @@ public class Constants { // migration public static final int MIGRATION_BATCH = 10; + + public static final String BATCH_SIZE = "batch_size"; } \ No newline at end of file diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 1baa6d14..6560c517 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -1,6 +1,7 @@ package community.icon.cps.score.cpstreasury; import community.icon.cps.score.cpstreasury.db.ProposalData; +import community.icon.cps.score.cpstreasury.utils.ArrayDBUtils; import score.*; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; @@ -513,4 +514,22 @@ public void ProposalFundSent(Address _receiver_address, String note) { public void ProposalFundWithdrawn(Address _receiver_address, String note) { } + /*----------------------------------------------------------------------------------------------------------------- + ***************************************************** to be removed in production********************************** + -----------------------------------------------------------------------------------------------------------------*/ + + @External + public void depositProposalFunds(ProposalData.ProposalAttributes proposals){ + addRecord(proposals); + } + + @External(readonly = true) + public String returnString(){ + return ""; + } + +// @External +// public void removeArrayItems(){ +// ArrayDBUtils.remove_array_item_address(contributorProjects); +// } } From 6b4ffb49cf76514c31b54cc60134de369446384b Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Sun, 27 Nov 2022 21:38:58 +0545 Subject: [PATCH 096/112] review changes --- .../icon/cps/score/cpscore/CPSCore.java | 55 +++---------------- 1 file changed, 9 insertions(+), 46 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 99998fd8..e55e5d9e 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -1172,28 +1172,8 @@ public Map>> get_project_amounts() { @External(readonly = true) public Map getSponsorsRecord() { - List proposalKeys = new ArrayList<>(); Map sponsorsDict = new HashMap<>(); - -// List activeProposals = get_proposals_keys_by_status(ACTIVE); -// proposalKeys.addAll(activeProposals); -// List pausedProposals = get_proposals_keys_by_status(PAUSED); -// proposalKeys.addAll(pausedProposals); -// List completedProposals = get_proposals_keys_by_status(COMPLETED); -// proposalKeys.addAll(completedProposals); -// -// for (String proposal : proposalKeys) { -// String proposalPrefix = proposalPrefix(proposal); -// String sponsorAddress = ProposalDataDb.sponsorAddress.at(proposalPrefix).get().toString(); -// int sponsorValue = 0; -// try { -// sponsorValue = sponsorsDict.get(sponsorAddress); -// } catch (Exception e) { -// sponsorsDict.put(sponsorAddress, 0); -// } -// -// sponsorsDict.put(sponsorAddress, sponsorValue + 1); -// } +// todo make var for size for (int i = 0; i < sponsors.size(); i++){ Address sponsorAddress = sponsors.get(i); sponsorsDict.put(sponsorAddress.toString(), sponsorProjects.at(sponsorAddress).size()); @@ -1616,7 +1596,7 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash) { startIndex = 0; } if ((endIndex - startIndex) > 10) { - return Map.of(MESSAGE, "Page length must not be greater than 50."); + return Map.of(MESSAGE, "Page length must not be greater than 10."); } int count = proposalKeys.size(); @@ -1683,7 +1663,7 @@ private Map getProgressReportDetails(String progressKey) { startIndex = 0; } if ((endIndex - startIndex) > 10) { - return Map.of(MESSAGE, "Page length must not be greater than 50."); + return Map.of(MESSAGE, "Page length must not be greater than 10."); } int count = progressReportKeys.size(); @@ -2479,28 +2459,22 @@ public Map getSponsorsReqInterScoreCall(String status, Address s if (!List.of(APPROVED, SPONSOR_PENDING, REJECTED, DISQUALIFIED).contains(status)) { return Map.of(MESSAGE, "Not a valid _status."); } - List proposalKeys = new ArrayList<>(); + List proposalKeys; List sponsorRequests = new ArrayList<>(); - + String prefix = ""; if (status.equals(APPROVED)) { proposalKeys = arrayDBtoList(this.sponsorProjects.at(sponsorAddress)); List pendingProposals = get_proposals_keys_by_status(PENDING); - String prefix = ""; - String ipfsKey = ""; - for (int i = 0; i < pendingProposals.size(); i++) { - ipfsKey = pendingProposals.get(i); + for (String ipfsKey : pendingProposals) { prefix = proposalPrefix(ipfsKey); if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { proposalKeys.add(ipfsKey); } } } else { - List pendingProposals = get_proposals_keys_by_status(status); - String prefix = ""; - String ipfsKey = ""; - for (int i = 0; i < pendingProposals.size(); i++) { - ipfsKey = pendingProposals.get(i); + proposalKeys = get_proposals_keys_by_status(status); + for (String ipfsKey : proposalKeys) { prefix = proposalPrefix(ipfsKey); if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { proposalKeys.add(ipfsKey); @@ -2521,7 +2495,7 @@ public Map getSponsorsReqInterScoreCall(String status, Address s BigInteger sponsorAmountICX = BigInteger.ZERO, sponsorAmountBnusd = BigInteger.ZERO; for (int i = startIndex; i < endIndex; i++) { - String proposalKey = (String) proposalKeys.get(i); + String proposalKey = proposalKeys.get(i); String proposalPrefix = proposalPrefix(proposalKey); String sponsorDepositStatus = ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).getOrDefault(""); if (sponsorDepositStatus.equals(BOND_APPROVED)) { @@ -2541,17 +2515,6 @@ public Map getSponsorsReqInterScoreCall(String status, Address s SPONSOR_DEPOSIT_AMOUNT, Map.of(ICX, sponsorAmountICX, bnUSD, sponsorAmountBnusd)); } - @External(readonly = true) - public String returnString() { - return ""; - } - - @External(readonly = true) - public String returnStringCon() { - SetterGetter setterGetter = new SetterGetter(); - return callScore(String.class, setterGetter.cpsTreasuryScore.get(), "returnString"); - } - @External public void migrateProposals() { validateAdmins(); From f972ae94529f971529fc5823413748bb1a48cd17 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 28 Nov 2022 16:29:26 +0545 Subject: [PATCH 097/112] added lisbon testnet address --- CPSCore/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle index af2fab01..83d25c3c 100644 --- a/CPSCore/build.gradle +++ b/CPSCore/build.gradle @@ -30,7 +30,7 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 - to = 'cx0546dc4c03491a0690b910b505eec537bbf377a5' + to = 'cxd82e5f0c1090f55f9b2f727ad35fb3a9e1de95c4' } local { uri = 'http://localhost:9082/api/v3' From c6dcd6228517465b3eda989671b93c903f0e907d Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 28 Nov 2022 16:30:22 +0545 Subject: [PATCH 098/112] fixed out of step issues in readonly methods --- .../icon/cps/score/cpscore/CPSCore.java | 269 ++++++------------ .../cps/score/cpscore/utils/Constants.java | 2 +- 2 files changed, 94 insertions(+), 177 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index e55e5d9e..8df992f8 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -73,8 +73,8 @@ public class CPSCore implements CPSCoreInterface { private final VarDB swapCount = Context.newVarDB(SWAP_COUNT, Integer.class); private final DictDB proposalRank = Context.newDictDB(PROPOSAL_RANK, Integer.class); private final ArrayDB
priorityVotedPreps = Context.newArrayDB(PRIORITY_VOTED_PREPS, Address.class); - private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS, String.class); - private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS, String.class); + private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS+"sssssssss", String.class); + private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS+"sssssssss", String.class); private final VarDB batchSize = Context.newVarDB(BATCH_SIZE, Integer.class); public CPSCore() { @@ -237,6 +237,11 @@ public boolean getMaintenanceMode() { return setterGetter.maintenance.getOrDefault(false); } + @External(readonly = true) + public boolean get_maintenance_mode() { + return getMaintenanceMode(); + } + @Override @Payable public void fallback() { @@ -293,7 +298,7 @@ public void removeAdmin(Address address) { // change made @External public void unregisterPrep() { checkMaintenance(); - update_period(); + updatePeriod(); Address caller = Context.getCaller(); PReps pReps = new PReps(); PeriodController period = new PeriodController(); @@ -319,7 +324,7 @@ public void unregister_prep() { public void registerPrep() { // todo: check PRep list for candidate PRep after snapshot checkMaintenance(); - update_period(); + updatePeriod(); Address caller = Context.getCaller(); List
prepList = getPrepsAddress(); PReps pReps = new PReps(); @@ -720,7 +725,7 @@ private BigInteger getMaxCapBNUsd() { @External public void submitProposal(ProposalAttributes proposals) { checkMaintenance(); - update_period(); + updatePeriod(); PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(APPLICATION_PERIOD), TAG + ": Proposals can only be submitted on Application Period "); @@ -769,7 +774,7 @@ public void submit_proposal(ProposalAttributes _proposals) { @External public void voteProposal(String ipfsKey, String vote, String voteReason, @Optional boolean voteChange) { checkMaintenance(); - update_period(); + updatePeriod(); PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(VOTING_PERIOD), TAG + ": Proposals can be voted only on Voting Period."); @@ -874,7 +879,7 @@ public void migrateAbstainVotes(Migration[] migrations) { @External public void submitProgressReport(ProgressReportAttributes progressReport) { checkMaintenance(); - update_period(); + updatePeriod(); PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(APPLICATION_PERIOD), TAG + ": Proposals can only be submitted on Application Period "); @@ -950,7 +955,7 @@ public void voteProgressReport(String ipfsKey, String reportKey, String vote, St } checkMaintenance(); - update_period(); + updatePeriod(); PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(VOTING_PERIOD), TAG + ": Progress Reports can be voted only on Voting Period."); @@ -1089,10 +1094,10 @@ public List get_proposals_keys_by_status(String _status) { public int checkChangeVote(Address address, String ipfsHash, String proposalType) { if (proposalType.equals(PROPOSAL)) { String proposalPrefix = proposalPrefix(ipfsHash); - return ProposalDataDb.votersListIndex.at(proposalPrefix).at(address).getOrDefault(CHANGE_VOTE, 0); + return ProposalDataDb.votersListIndex.at(proposalPrefix).at(address).getOrDefault(CHANGE_VOTE, NOT_VOTED); } else if (proposalType.equals(PROGRESS_REPORTS)) { String progressReportPrefix = progressReportPrefix(ipfsHash); - return votersListIndices.at(progressReportPrefix).at(address).getOrDefault(CHANGE_VOTE, 0); + return votersListIndices.at(progressReportPrefix).at(address).getOrDefault(CHANGE_VOTE, NOT_VOTED); } else { return 0; } @@ -1124,7 +1129,7 @@ public Map>> getProjectAmounts() { BigInteger amountICX = BigInteger.ZERO; BigInteger amountBnusd = BigInteger.ZERO; - List proposalsKeysByStatus = this.get_proposals_keys_by_status(statusList.get(statusId)); + List proposalsKeysByStatus = this.getProposalsKeysByStatus(statusList.get(statusId)); for (String proposalKey : proposalsKeysByStatus) { String proposalPrefix = proposalPrefix(proposalKey); BigInteger projectBudget = ProposalDataDb.totalBudget.at(proposalPrefix).getOrDefault(BigInteger.ZERO); @@ -1173,8 +1178,8 @@ public Map>> get_project_amounts() { @External(readonly = true) public Map getSponsorsRecord() { Map sponsorsDict = new HashMap<>(); -// todo make var for size - for (int i = 0; i < sponsors.size(); i++){ + int size = sponsors.size(); + for (int i = 0; i < size; i++) { Address sponsorAddress = sponsors.get(i); sponsorsDict.put(sponsorAddress.toString(), sponsorProjects.at(sponsorAddress).size()); } @@ -1590,7 +1595,7 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash) { return Map.of(MESSAGE, "Not a valid _status."); } List proposalsList = new ArrayList<>(); - List proposalKeys = get_proposals_keys_by_status(status); + List proposalKeys = getProposalsKeysByStatus(status); if (startIndex < 0) { startIndex = 0; @@ -1742,23 +1747,27 @@ public Map getSponsorsRequests(String status, Address sponsorAdd if (!List.of(APPROVED, SPONSOR_PENDING, REJECTED, DISQUALIFIED).contains(status)) { return Map.of(MESSAGE, "Not a valid _status."); } - List proposalKeys = new ArrayList<>(); + List proposalKeys; List sponsorRequests = new ArrayList<>(); + String prefix = ""; if (status.equals(APPROVED)) { - List pendingProposals = get_proposals_keys_by_status(PENDING); - proposalKeys.addAll(pendingProposals); - List activeProposals = get_proposals_keys_by_status(ACTIVE); - proposalKeys.addAll(activeProposals); - List pausedProposals = get_proposals_keys_by_status(PAUSED); - proposalKeys.addAll(pausedProposals); - List completedProposals = get_proposals_keys_by_status(COMPLETED); - proposalKeys.addAll(completedProposals); - - + proposalKeys = arrayDBtoList(this.sponsorProjects.at(sponsorAddress)); + List pendingProposals = getProposalsKeysByStatus(PENDING); + for (String ipfsKey : pendingProposals) { + prefix = proposalPrefix(ipfsKey); + if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { + proposalKeys.add(ipfsKey); + } + } } else { - List proposalKey = get_proposals_keys_by_status(status); - proposalKeys.addAll(proposalKey); + proposalKeys = getProposalsKeysByStatus(status); + for (String ipfsKey : proposalKeys) { + prefix = proposalPrefix(ipfsKey); + if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { + proposalKeys.add(ipfsKey); + } + } } if (startIndex < 0) { startIndex = 0; @@ -1774,24 +1783,22 @@ public Map getSponsorsRequests(String status, Address sponsorAdd BigInteger sponsorAmountICX = BigInteger.ZERO, sponsorAmountBnusd = BigInteger.ZERO; for (int i = startIndex; i < endIndex; i++) { - String proposalKey = (String) proposalKeys.get(i); + String proposalKey = proposalKeys.get(i); String proposalPrefix = proposalPrefix(proposalKey); - Address proposalSponsor = ProposalDataDb.sponsorAddress.at(proposalPrefix).get(); - if (proposalSponsor.equals(sponsorAddress)) { - String sponsorDepositStatus = ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).getOrDefault(""); - if (sponsorDepositStatus.equals(BOND_APPROVED)) { - Map proposalDetails = getProposalDetails(proposalKey); - String token = (String) proposalDetails.get(TOKEN); - BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); - if (token.equals(ICX)) { - sponsorAmountICX = sponsorAmountICX.add(sponsorDepositAmount); - } else if (token.equals(bnUSD)) { - sponsorAmountBnusd = sponsorAmountBnusd.add(sponsorDepositAmount); - } - sponsorRequests.add(proposalDetails); + String sponsorDepositStatus = ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).getOrDefault(""); + if (sponsorDepositStatus.equals(BOND_APPROVED)) { + Map proposalDetails = getProposalDetails(proposalKey); + String token = (String) proposalDetails.get(TOKEN); + BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); + if (token.equals(ICX)) { + sponsorAmountICX = sponsorAmountICX.add(sponsorDepositAmount); + } else if (token.equals(bnUSD)) { + sponsorAmountBnusd = sponsorAmountBnusd.add(sponsorDepositAmount); } + sponsorRequests.add(proposalDetails); } } + return Map.of(DATA, sponsorRequests, COUNT, sponsorRequests.size(), SPONSOR_DEPOSIT_AMOUNT, Map.of(ICX, sponsorAmountICX, bnUSD, sponsorAmountBnusd)); } @@ -1816,7 +1823,7 @@ public List> get_remaining_project(String _project_type, Add List> _remaining_proposals = new ArrayList<>(); List> _remaining_progress_report = new ArrayList<>(); if (_project_type.equals(PROPOSAL)) { - List _proposal_keys = get_proposals_keys_by_status(PENDING); + List _proposal_keys = getProposalsKeysByStatus(PENDING); for (String _ipfs_key : _proposal_keys) { String prefix = proposalPrefix(_ipfs_key); @@ -2017,7 +2024,7 @@ private void updateApplicationResult() { period.periodName.set(APPLICATION_PERIOD); PeriodUpdate("Period Updated back to Application Period due to less Registered P-Reps Count"); - } else if (get_proposals_keys_by_status(PENDING).size() == 0 && this.progressReportStatus.get(WAITING).size() == 0 && activeProposals.size() + paused.size() == 0) { + } else if (getProposalsKeysByStatus(PENDING).size() == 0 && this.progressReportStatus.get(WAITING).size() == 0 && activeProposals.size() + paused.size() == 0) { createActiveProposalDb(); checkProgressReportSubmission(); period.periodName.set(APPLICATION_PERIOD); @@ -2053,7 +2060,7 @@ private void createActiveProposalDb() { private void payPrepPenalty(Address from, BigInteger _value) { checkMaintenance(); - update_period(); + updatePeriod(); PReps pReps = new PReps(); PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(APPLICATION_PERIOD), @@ -2100,7 +2107,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { private void sponsorVote(String ipfsKey, String vote, String voteReason, Address from, BigInteger value) { checkMaintenance(); - update_period(); + updatePeriod(); PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(APPLICATION_PERIOD), TAG + " Sponsor Vote can only be done on Application Period"); @@ -2258,9 +2265,9 @@ public List> getActiveProposals() { List proposalKeys = new ArrayList<>(); List> activeProposalsMap = new ArrayList<>(); - List activeProposals = get_proposals_keys_by_status(ACTIVE); + List activeProposals = getProposalsKeysByStatus(ACTIVE); proposalKeys.addAll(activeProposals); - List pausedProposals = get_proposals_keys_by_status(PAUSED); + List pausedProposals = getProposalsKeysByStatus(PAUSED); proposalKeys.addAll(pausedProposals); for (String proposal : proposalKeys) { @@ -2307,11 +2314,11 @@ public List> getProposalsHistory() { List proposalKeys = new ArrayList<>(); List> activeProposalsMap = new ArrayList<>(); - List completedProjects = get_proposals_keys_by_status(COMPLETED); + List completedProjects = getProposalsKeysByStatus(COMPLETED); proposalKeys.addAll(completedProjects); - List rejectedProposals = get_proposals_keys_by_status(REJECTED); + List rejectedProposals = getProposalsKeysByStatus(REJECTED); proposalKeys.addAll(rejectedProposals); - List disqualifiedProjects = get_proposals_keys_by_status(DISQUALIFIED); + List disqualifiedProjects = getProposalsKeysByStatus(DISQUALIFIED); proposalKeys.addAll(disqualifiedProjects); for (String proposal : proposalKeys) { @@ -2399,142 +2406,52 @@ private void logger(String msg) { Context.println(msg); } - - //***************************************************************************************************************** - /* - to be removed in production, for testing only - */ - //***************************************************************************************************************** - @External - public void add_proposals(ProposalAttributes proposals) { - String proposalPrefix = proposalPrefix(proposals.ipfs_hash); - if (proposalsKeyListIndex.getOrDefault(proposals.ipfs_hash, 0) == 0) { - proposalsKeyList.add(proposals.ipfs_hash); - proposalsKeyListIndex.set(proposals.ipfs_hash, proposalsKeyList.size()); - contributors.add(Context.getCaller()); -// contributorProjects.at(Context.getCaller()).add(proposals.ipfs_hash); - addDataToProposalDB(proposals, proposalPrefix); - } - } - - @External - public void changeStatus(String proposalKey, String status) { - Context.require(ArrayDBUtils.containsInList(status, STATUS_TYPE)); - ProposalDataDb.status.at(proposalPrefix(proposalKey)).set(status); - proposalStatus.get(status).add(proposalKey); - sponsorDepositStatus.at(proposalPrefix(proposalKey)).set(BOND_APPROVED); - if(!status.equals(PENDING)){ -// sponsorProjects.at(sponsorAddress.at(proposalPrefix(proposalKey)).get()).add(proposalKey); - sponsors.add(sponsorAddress.at(proposalPrefix(proposalKey)).get()); - } - } - - @External - public void changeVoteData(String proposalKey, Address address, String vote) { - String prefix = proposalPrefix(proposalKey); - ProposalDataDb.totalVoters.at(prefix).set(12); - ProposalDataDb.totalVotes.at(prefix).set(BigInteger.valueOf(12000)); - ProposalDataDb.votersList.at(prefix).add(address); - votersListIndex.at(prefix).at(address).set(INDEX, ProposalDataDb.votersList.at(prefix).size()); - if (vote.equals(APPROVE)) { - ProposalDataDb.approvedVotes.at(prefix).set(ProposalDataDb.approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO).add(BigInteger.valueOf(1000))); - ProposalDataDb.approveVoters.at(prefix).add(address); - votersListIndex.at(prefix).at(address).set(VOTE, APPROVE_); - } else if (vote.equals(REJECT)) { - ProposalDataDb.rejectedVotes.at(prefix).set(ProposalDataDb.rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO).add(BigInteger.valueOf(1000))); - ProposalDataDb.rejectVoters.at(prefix).add(address); - votersListIndex.at(prefix).at(address).set(VOTE, REJECT_); - } else { - abstainedVotes.at(prefix).set(abstainedVotes.at(prefix).getOrDefault(BigInteger.ZERO).add(BigInteger.valueOf(1000))); - abstainVoters.at(prefix).add(address); - votersListIndex.at(prefix).at(address).set(VOTE, ABSTAIN_); - } - } - - @External(readonly = true) - public Map getSponsorsReqInterScoreCall(String status, Address sponsorAddress, @Optional int startIndex, @Optional int endIndex) { - if (endIndex == 0) { - endIndex = 20; - } - if (!List.of(APPROVED, SPONSOR_PENDING, REJECTED, DISQUALIFIED).contains(status)) { - return Map.of(MESSAGE, "Not a valid _status."); - } - List proposalKeys; - List sponsorRequests = new ArrayList<>(); - String prefix = ""; - - if (status.equals(APPROVED)) { - proposalKeys = arrayDBtoList(this.sponsorProjects.at(sponsorAddress)); - List pendingProposals = get_proposals_keys_by_status(PENDING); - for (String ipfsKey : pendingProposals) { - prefix = proposalPrefix(ipfsKey); - if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { - proposalKeys.add(ipfsKey); - } - } - } else { - proposalKeys = get_proposals_keys_by_status(status); - for (String ipfsKey : proposalKeys) { - prefix = proposalPrefix(ipfsKey); - if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { - proposalKeys.add(ipfsKey); - } - } - } - if (startIndex < 0) { - startIndex = 0; - } - if ((endIndex - startIndex) > 50) { - return Map.of(MESSAGE, "Page length must not be greater than 50."); - } - int count = proposalKeys.size(); - if (endIndex > count) { - endIndex = count; - } - - BigInteger sponsorAmountICX = BigInteger.ZERO, sponsorAmountBnusd = BigInteger.ZERO; - - for (int i = startIndex; i < endIndex; i++) { - String proposalKey = proposalKeys.get(i); - String proposalPrefix = proposalPrefix(proposalKey); - String sponsorDepositStatus = ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).getOrDefault(""); - if (sponsorDepositStatus.equals(BOND_APPROVED)) { - Map proposalDetails = getProposalDetails(proposalKey); - String token = (String) proposalDetails.get(TOKEN); - BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); - if (token.equals(ICX)) { - sponsorAmountICX = sponsorAmountICX.add(sponsorDepositAmount); - } else if (token.equals(bnUSD)) { - sponsorAmountBnusd = sponsorAmountBnusd.add(sponsorDepositAmount); - } - sponsorRequests.add(proposalDetails); - } - } - - return Map.of(DATA, sponsorRequests, COUNT, sponsorRequests.size(), - SPONSOR_DEPOSIT_AMOUNT, Map.of(ICX, sponsorAmountICX, bnUSD, sponsorAmountBnusd)); - } - @External public void migrateProposals() { validateAdmins(); - int startIndex = batchSize.getOrDefault(0); + int startIndex = batchSize.get(); int size = proposalsKeyList.size(); int endIndex = startIndex + 10; if (endIndex > size) { endIndex = size; } + List statusType = List.of(SPONSOR_PENDING, REJECTED, DISQUALIFIED, PENDING); + String status; + Address sponsor; + String prefix; + String ipfsKey; + Address contributor; for (int i = startIndex; i < endIndex; i++) { - String proposalKey = proposalsKeyList.get(i); - String prefix = proposalPrefix(proposalKey); - Address sponsorAddress = ProposalDataDb.sponsorAddress.at(prefix).get(); - Address contributorAddress = ProposalDataDb.contributorAddress.at(prefix).get(); - String proposalStatus = ProposalDataDb.status.at(prefix).get(); - if (!List.of(SPONSOR_PENDING, REJECTED, DISQUALIFIED, PENDING).contains(proposalStatus)) { - sponsorProjects.at(sponsorAddress).add(proposalKey); + ipfsKey = proposalsKeyList.get(i); + prefix = proposalPrefix(ipfsKey); + sponsor = sponsorAddress.at(prefix).get(); + contributor = contributorAddress.at(prefix).get(); + status = ProposalDataDb.status.at(prefix).get(); + if (!ArrayDBUtils.containsInList(status, statusType)) { + if (!ArrayDBUtils.containsInArrayDb(ipfsKey, sponsorProjects.at(sponsor))) { + sponsorProjects.at(sponsor).add(ipfsKey); + } + } + if (!ArrayDBUtils.containsInArrayDb(ipfsKey, contributorProjects.at(contributor))) { + contributorProjects.at(contributor).add(ipfsKey); } - contributorProjects.at(contributorAddress).add(proposalKey); + batchSize.set(endIndex); } - batchSize.set(endIndex); } + @External(readonly = true) + public List getSponsorProjects(Address sponsor) { + return arrayDBtoList(sponsorProjects.at(sponsor)); + } + + @External(readonly = true) + public int getBatchSize() { + return batchSize.get(); + } + + @External + public void setBatchSize(){ + validateAdmins(); + batchSize.set(0); + } + } \ No newline at end of file diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java index bbfb63fc..45c4e364 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java @@ -143,7 +143,7 @@ public class Constants { public static final String PROPOSAL_RANK = "proposal_rank"; public static final String PRIORITY_VOTED_PREPS = "priority_voted_preps"; public static final String SPONSOR_PROJECTS = "sponsor_projects"; - public static final String CONTRIBUTOR_PROJECTS = "sponsor_projects"; + public static final String CONTRIBUTOR_PROJECTS = "contributor_projects"; // VOTE KEYS From dd06a1aaf62222293f9e217a1e3564995e2a716d Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 28 Nov 2022 18:44:37 +0545 Subject: [PATCH 099/112] added sejong testnet address --- CPSCore/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle index 83d25c3c..c8896a42 100644 --- a/CPSCore/build.gradle +++ b/CPSCore/build.gradle @@ -40,6 +40,11 @@ deployJar { uri = 'https://berlin.net.solidwallet.io/api/v3' nid = 0x7 } + sejong { + uri = 'https://sejong.net.solidwallet.io/api/v3' + nid = 0x53 + to = 'cx2b214d56805531b9c878c4d4ff0e53d961c60834' + } mainnet { uri = 'https://ctz.solidwallet.io/api/v3' nid = 0x1 From 54c75f46c7c4d87ec278f9c3147b5eecf1ad651f Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 28 Nov 2022 18:45:17 +0545 Subject: [PATCH 100/112] review fixes --- .../icon/cps/score/cpscore/CPSCore.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 8df992f8..7a7a5bce 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -66,7 +66,7 @@ public class CPSCore implements CPSCoreInterface { ); private final BranchDB> sponsorBondReturn = Context.newBranchDB(SPONSOR_BOND_RETURN, BigInteger.class); - private final DictDB delegationSnapshot = Context.newDictDB(DELEGATION_SNAPSHOT, BigInteger.class); + private final DictDB delegationSnapshot = Context.newDictDB(DELEGATION_SNAPSHOT, BigInteger.class); private final VarDB maxDelegation = Context.newVarDB(MAX_DELEGATION, BigInteger.class); private final VarDB proposalFees = Context.newVarDB(PROPOSAL_FEES, BigInteger.class); private final VarDB swapBlockHeight = Context.newVarDB(SWAP_BLOCK_HEIGHT, BigInteger.class); @@ -798,7 +798,7 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option } Context.require(status.equals(PENDING), TAG + ": Proposal must be done in Voting state."); - BigInteger voterStake = delegationSnapshot.get(String.valueOf(caller)); + BigInteger voterStake = delegationSnapshot.get(caller); BigInteger totalVotes = (BigInteger) proposalDetails.get(TOTAL_VOTES); BigInteger approvedVotes = (BigInteger) proposalDetails.get(APPROVED_VOTES); BigInteger rejectedVotes = (BigInteger) proposalDetails.get(REJECTED_VOTES); @@ -818,7 +818,7 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option } else { Context.require(votersIndexDb.getOrDefault(CHANGE_VOTE, 0) == 0, TAG + ": Vote change can be done only once."); - votersIndexDb.set(CHANGE_VOTE, 1); + votersIndexDb.set(CHANGE_VOTE, VOTED); int index = votersIndexDb.getOrDefault(INDEX, 0); int voteIndex = votersIndexDb.getOrDefault(VOTE, 0); ProposalDataDb.votersReasons.at(proposalPrefix).set(index - 1, voteReason); @@ -832,9 +832,9 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option ArrayDBUtils.removeArrayItem(abstainVoters.at(proposalPrefix), caller); ProposalDataDb.abstainedVotes.at(proposalPrefix).set(abstainedVotes.subtract(voterStake)); } - approvedVotes = (BigInteger) proposalDetails.get(APPROVED_VOTES); - rejectedVotes = (BigInteger) proposalDetails.get(REJECTED_VOTES); - abstainedVotes = (BigInteger) proposalDetails.get(ABSTAINED_VOTES); + approvedVotes = ProposalDataDb.approvedVotes.at(proposalPrefix).getOrDefault(BigInteger.ZERO); + rejectedVotes = ProposalDataDb.rejectedVotes.at(proposalPrefix).getOrDefault(BigInteger.ZERO); + abstainedVotes = ProposalDataDb.abstainedVotes.at(proposalPrefix).getOrDefault(BigInteger.ZERO); } if (vote.equals(APPROVE)) { @@ -979,7 +979,7 @@ public void voteProgressReport(String ipfsKey, String reportKey, String vote, St } if (status.equals(WAITING)) { - BigInteger voterStake = delegationSnapshot.get(String.valueOf(caller)); + BigInteger voterStake = delegationSnapshot.get(caller); BigInteger totalVotes = (BigInteger) progressReportDetails.get(TOTAL_VOTES); BigInteger approvedVotes = (BigInteger) progressReportDetails.get(APPROVED_VOTES); BigInteger rejectedVotes = (BigInteger) progressReportDetails.get(REJECTED_VOTES); @@ -997,7 +997,7 @@ public void voteProgressReport(String ipfsKey, String reportKey, String vote, St } else { Context.require(votersIndexDb.getOrDefault(CHANGE_VOTE, 0) == 0, TAG + ": Progress Report Vote change can be done only once."); - votersIndexDb.set(CHANGE_VOTE, 1); + votersIndexDb.set(CHANGE_VOTE, VOTED); int index = votersIndexDb.getOrDefault(INDEX, 0); int voteIndex = votersIndexDb.getOrDefault(VOTE, 0); ProgressReportDataDb.votersReasons.at(progressReportPrefix).set(index - 1, voteReason); @@ -1024,8 +1024,8 @@ public void voteProgressReport(String ipfsKey, String reportKey, String vote, St } } - approvedVotes = (BigInteger) progressReportDetails.get(APPROVED_VOTES); - rejectedVotes = (BigInteger) progressReportDetails.get(REJECTED_VOTES); + approvedVotes = ProgressReportDataDb.approvedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); + rejectedVotes = ProgressReportDataDb.rejectedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); } if (vote.equals(APPROVE)) { @@ -1042,8 +1042,8 @@ public void voteProgressReport(String ipfsKey, String reportKey, String vote, St } if (ArrayDBUtils.containsInArrayDb(reportKey, budgetApprovalsList)) { - BigInteger budgetApprovedVotes = (BigInteger) progressReportDetails.get(BUDGET_APPROVED_VOTES); - BigInteger budgetRejectedVotes = (BigInteger) progressReportDetails.get(BUDGET_REJECTED_VOTES); + BigInteger budgetApprovedVotes = ProgressReportDataDb.budgetApprovedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); + BigInteger budgetRejectedVotes = ProgressReportDataDb.budgetRejectedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); DictDB budgetVoteIndex = budgetVotersListIndices.at(progressReportPrefix).at(caller); if (budgetAdjustmentVote.equals(APPROVE)) { ProgressReportDataDb.budgetApproveVoters.at(progressReportPrefix).add(caller); @@ -2009,7 +2009,7 @@ private void snapshotDelegation() { for (int i = 0; i < pReps.validPreps.size(); i++) { Address prep = pReps.validPreps.get(i); BigInteger stake = getStake(prep); - delegationSnapshot.set(prep.toString(), stake); + delegationSnapshot.set(prep, stake); if (stake.compareTo(maxDelegation) > 0) { maxDelegation = stake; } From c24cd40b07fd6f8332f5ed73cf47cc08eb7ea552 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 28 Nov 2022 21:28:17 +0545 Subject: [PATCH 101/112] changed method interfaces --- .../icon/cps/score/lib/interfaces/CPSCoreInterface.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java index a2b10d21..4aead781 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java @@ -258,16 +258,16 @@ public static class ProgressReportAttributes { @External - void update_next_block(int blockCount); + void updateNextBlock(int blockCount); @External(readonly = true) - List> get_active_proposals(); + Map getActiveProposals(@Optional int startIndex); @External(readonly = true) Map get_proposal_detail_by_wallet(Address _wallet_address); - List> getProposalsHistory(); + Map getProposalsHistory(@Optional int startIndex); // EventLogs @EventLog(indexed = 1) From 3581a5cbc9b429b14f0268797bdd4af33a501181 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 28 Nov 2022 21:28:44 +0545 Subject: [PATCH 102/112] changed tests after the fixes in the main score --- .../icon/cps/score/cpscore/CPSScoreTest.java | 129 ++++++++++++++++-- 1 file changed, 114 insertions(+), 15 deletions(-) diff --git a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java index 99e6f4a4..1c02941d 100644 --- a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java +++ b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java @@ -37,6 +37,7 @@ import java.math.BigInteger; import java.nio.channels.MulticastChannel; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -399,7 +400,7 @@ void submitProposal(){ assertEquals(owner.getAddress(), proposalDetails.get("contributor_address")); assertEquals("_sponsor_pending", proposalDetails.get("status")); assertEquals(BigInteger.valueOf(100).multiply(MULTIPLIER), proposalDetails.get("total_budget")); - Map proposalDetailsOfStatus = (Map) cpsScore.call("getProposalDetails", SPONSOR_PENDING, owner.getAddress(), 0, 20); + Map proposalDetailsOfStatus = (Map) cpsScore.call("getProposalDetails", SPONSOR_PENDING, owner.getAddress(), 0, 10); assertEquals(1, proposalDetailsOfStatus.get(COUNT)); assertEquals(proposalDetails, ((List>)proposalDetailsOfStatus.get(DATA)).get(0)); @@ -575,6 +576,100 @@ void voteProposalMethod(){ cpsScore.invoke(owner, "votePriority", (Object) proposal); } + @Test + void submitMultipleProposals(){ + registerPrepsMethod(); + Map remainingSwapAmount = Map.of( + "remaining_swap_amount", BigInteger.valueOf(1000).multiply(MULTIPLIER), + "maxCap", BigInteger.valueOf(1000).multiply(MULTIPLIER)); + doReturn(remainingSwapAmount).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_remaining_swap_amount")); + contextMock.when(() -> Context.getValue()).thenReturn(BigInteger.valueOf(50).multiply(MULTIPLIER)); + byte [] tx_hash = "transaction".getBytes(); + contextMock.when(() -> Context.getTransactionHash()).thenReturn(tx_hash); + doNothing().when(scoreSpy).callScore(eq(BigInteger.valueOf(25).multiply(MULTIPLIER)), eq(SYSTEM_ADDRESS), eq("burn")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(0)); + for (int i = 0; i < 10; i++) { + ProposalAttributes proposalAttributes = new ProposalAttributes(); + proposalAttributes.ipfs_hash = "Proposal " + i; + proposalAttributes.project_title = "Title"; + proposalAttributes.project_duration = 2; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = testingAccount.getAddress(); + proposalAttributes.ipfs_link = "link"; + cpsScore.invoke(owner, "submitProposal", proposalAttributes); + } + contextMock.when(caller()).thenReturn(bnUSDScore); + JsonObject sponsorVoteParams = new JsonObject(); + sponsorVoteParams.add("method", "sponsor_vote"); + JsonObject params = new JsonObject(); + for (int i = 0; i < 10; i++) { + params.add(IPFS_HASH, "Proposal " + i); + params.add(VOTE, ACCEPT); + params.add(VOTE_REASON, "reason"); + sponsorVoteParams.add("params", params); + + cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), BigInteger.valueOf(10).multiply(MULTIPLIER), sponsorVoteParams.toString().getBytes()); + } + } + + @Test + void voteMultipleProposals(){ + submitMultipleProposals(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + cpsScore.invoke(owner, "update_period"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), any()); + String[] proposal = new String[]{"Proposal 0","Proposal 1","Proposal 2","Proposal 3","Proposal 4","Proposal 5", + "Proposal 6","Proposal 7","Proposal 8","Proposal 9"}; + + for (int i = 0; i < 10; i++) { + contextMock.when(caller()).thenReturn(owner.getAddress()); + cpsScore.invoke(owner, "voteProposal", "Proposal " + i, APPROVE, "reason", false); + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProposal", "Proposal " + i, APPROVE, "reason", false); + + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProposal", "Proposal " + i, APPROVE, "reason", false); + + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProposal", "Proposal " + i, APPROVE, "reason", false); + + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProposal", "Proposal " + i, APPROVE, "reason", false); + + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProposal", "Proposal " + i, APPROVE, "reason", false); + + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProposal", "Proposal " + i, APPROVE, "reason", false); +} + + contextMock.when(caller()).thenReturn(owner.getAddress()); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + } + void voteProposalMethodReject(){ submitAndSponsorVote(); contextMock.when(caller()).thenReturn(owner.getAddress()); @@ -643,9 +738,9 @@ void updatePeriodAfterProposalVoting(){ updatePeriods(); Map proposalDetails = getProposalDetailsByHash("Proposal 1"); - List> activeProposals = (List>) cpsScore.call("getActiveProposals"); + Map activeProposals = (Map) cpsScore.call("getActiveProposals", 0); assertEquals(ACTIVE, proposalDetails.get("status")); - assertEquals(List.of(proposalDetails), activeProposals); + assertEquals(List.of(proposalDetails), activeProposals.get(DATA)); Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); System.out.println("Sponsors request" + sponosrsRequest); @@ -695,8 +790,8 @@ void rejectProposal(){ Map voteResult = (Map) cpsScore.call("getVoteResult", "Proposal 1"); System.out.println("voteResult: " + voteResult); - List> proposalsHistory = (List>) cpsScore.call("getProposalsHistory"); - assertEquals(proposalDetails, proposalsHistory.get(0)); + Map proposalsHistory = (Map) cpsScore.call("getProposalsHistory", 0); + assertEquals(List.of(proposalDetails), proposalsHistory.get(DATA)); } @Test @@ -731,7 +826,8 @@ void submitProgressReport(){ List progressKeys = (List) cpsScore.call("getProgressKeys"); assertEquals(List.of("Report 1"), progressKeys); - Map progressReports = (Map) cpsScore.call("getProgressReports", WAITING, 0, 20); + Map progressReports = (Map) cpsScore.call("getProgressReports", WAITING, 0, 10); + System.out.println("Progerss reports: " + progressReports); assertEquals(List.of(progressReportDetails), progressReports.get(DATA)); assertEquals(1, progressReports.get(COUNT)); @@ -985,8 +1081,8 @@ void voteProgressReportAfterSubmittingProposalWithoutBudgetAdjustment(){ Map claimableSponsorBond = (Map) cpsScore.call("checkClaimableSponsorBond", testingAccount.getAddress()); assertEquals(BigInteger.valueOf(10).multiply(MULTIPLIER), claimableSponsorBond.get(bnUSD)); - List> proposalsHistory = (List>) cpsScore.call("getProposalsHistory"); - assertEquals(proposalDetails, proposalsHistory.get(0)); + Map proposalsHistory = (Map) cpsScore.call("getProposalsHistory", 0); + assertEquals(List.of(proposalDetails), proposalsHistory.get(DATA)); } @Test @@ -1002,16 +1098,19 @@ void claimSponsorBond(){ @Test void sortPriorityProposals(){ - voteProposalMethod(); - @SuppressWarnings("unchecked") + voteMultipleProposals(); + List proposal = List.of("Proposal 0","Proposal 1","Proposal 2","Proposal 3","Proposal 4","Proposal 5", + "Proposal 6","Proposal 7","Proposal 8","Proposal 9"); +// @SuppressWarnings("unchecked") List proposalList = (List) cpsScore.call("sortPriorityProposals"); - assertEquals(List.of("Proposal 1"), proposalList); + assertEquals(proposal, proposalList); @SuppressWarnings("unchecked") Map priorityVoteResult = (Map) cpsScore.call("getPriorityVoteResult"); - assertEquals(Map.of("Proposal 1", 7), priorityVoteResult); + System.out.println(priorityVoteResult); } + @Test void setCpsTreasury(){ contextMock.when(caller()).thenReturn(owner.getAddress()); @@ -1167,8 +1266,8 @@ void disqualifyProposal(){ ); assertEquals(amount, (projectAmounts.get(DISQUALIFIED))); - List> proposalsHistory = (List>) cpsScore.call("getProposalsHistory"); - assertEquals(proposalDetails, proposalsHistory.get(0)); + Map proposalsHistory = (Map) cpsScore.call("getProposalsHistory", 0); + assertEquals(List.of(proposalDetails), proposalsHistory.get(DATA)); } @Test @@ -1344,7 +1443,7 @@ void fallback(){ @Test void getPeriodCount(){ - assertEquals(19, cpsScore.call("getPeriodCount")); + assertEquals(20, cpsScore.call("getPeriodCount")); } From b3dd293577570f95be7b77fe4fddbb78a3583cd2 Mon Sep 17 00:00:00 2001 From: parajuliswopnil Date: Mon, 28 Nov 2022 21:29:12 +0545 Subject: [PATCH 103/112] review fixes --- .../icon/cps/score/cpscore/CPSCore.java | 86 +++++++------------ 1 file changed, 31 insertions(+), 55 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 7a7a5bce..e93b46bc 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -73,13 +73,14 @@ public class CPSCore implements CPSCoreInterface { private final VarDB swapCount = Context.newVarDB(SWAP_COUNT, Integer.class); private final DictDB proposalRank = Context.newDictDB(PROPOSAL_RANK, Integer.class); private final ArrayDB
priorityVotedPreps = Context.newArrayDB(PRIORITY_VOTED_PREPS, Address.class); - private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS+"sssssssss", String.class); - private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS+"sssssssss", String.class); + private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS, String.class); + private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS, String.class); private final VarDB batchSize = Context.newVarDB(BATCH_SIZE, Integer.class); public CPSCore() { PeriodController periodController = new PeriodController(); - periodController.periodCount.set(19); + periodController.periodCount.set(20); + batchSize.set(0); } @Override @@ -729,7 +730,7 @@ public void submitProposal(ProposalAttributes proposals) { PeriodController period = new PeriodController(); Context.require(period.periodName.get().equals(APPLICATION_PERIOD), TAG + ": Proposals can only be submitted on Application Period "); - Context.require(proposalsKeyListIndex.getOrDefault(proposals.ipfs_hash, 0) == 0, TAG + ": Proposal key already exists."); + Context.require(!proposalKeyExists(proposals.ipfs_hash), TAG + ": Proposal key already exists."); Context.require(!Context.getCaller().isContract(), TAG + ": Contract Address not supported."); Context.require(proposals.project_duration <= MAX_PROJECT_PERIOD, TAG + ": Maximum Project Duration exceeds " + MAX_PROJECT_PERIOD + " months."); @@ -905,7 +906,7 @@ public void submitProgressReport(ProgressReportAttributes progressReport) { String reportHash = progressReport.report_hash; String ipfsHash = progressReport.ipfs_hash; Context.require(!_progress_key_exists(reportHash), TAG + ": Report key already exists."); - Context.require(proposalKeyExists(ipfsHash)); + Context.require(proposalKeyExists(ipfsHash), TAG + ": Invalid proposal key"); addNewProgressReportKey(ipfsHash, reportHash); String reportHashPrefix = progressReportPrefix(reportHash); addDataToProgressReportDB(progressReport, reportHashPrefix); @@ -1608,7 +1609,6 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash) { if (endIndex > count) { endIndex = count; } -// endIndex = ((endIndex > count) ? endIndex : count); for (int i = startIndex; i < endIndex; i++) { String proposalKey = proposalKeys.get(i); @@ -2230,6 +2230,7 @@ public int getSwapCount() { return swapCount.get(); } + @Override @External public void updateNextBlock(int blockCount) { validateAdmins(); @@ -2237,13 +2238,6 @@ public void updateNextBlock(int blockCount) { period.nextBlock.set(BigInteger.valueOf(Context.getBlockHeight() + blockCount)); } - @Override - @External - @Deprecated(since = "JAVA translation", forRemoval = true) - public void update_next_block(int blockCount) { - updateNextBlock(blockCount); - } - private void disqualifyProject(Address sponsorAddress, BigInteger sponsorDepositAmount, String flag) { Context.require(flag.equals(bnUSD), TAG + " Not supported Token"); JsonObject disqualifyProject = new JsonObject(); @@ -2256,33 +2250,29 @@ private void disqualifyProject(Address sponsorAddress, BigInteger sponsorDeposit sponsorDepositAmount, disqualifyProject.toString().getBytes()); SponsorBondReturned(cpfScore, "Project Disqualified. " + sponsorDepositAmount + " " + flag + " returned to CPF Treasury Address."); - - } @External(readonly = true) - public List> getActiveProposals() { + public Map getActiveProposals(@Optional int startIndex) { List proposalKeys = new ArrayList<>(); - List> activeProposalsMap = new ArrayList<>(); + List> activeProposalsList = new ArrayList<>(); List activeProposals = getProposalsKeysByStatus(ACTIVE); proposalKeys.addAll(activeProposals); List pausedProposals = getProposalsKeysByStatus(PAUSED); proposalKeys.addAll(pausedProposals); - for (String proposal : proposalKeys) { - Map proposalDetails = getProposalDetails(proposal); - activeProposalsMap.add(proposalDetails); - + int endIndex = startIndex + 10; + int size = proposalKeys.size(); + if (endIndex > size){ + endIndex = size; } - return activeProposalsMap; - } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public List> get_active_proposals() { - return getActiveProposals(); + for (int i = startIndex; i < endIndex; i++) { + Map proposalDetails = getProposalDetails(proposalKeys.get(i)); + activeProposalsList.add(proposalDetails); + } + return Map.of(DATA, activeProposalsList, COUNT, size); } /*** @@ -2309,10 +2299,10 @@ public Map get_proposal_detail_by_wallet(Address _wallet_address } @Override - @External - public List> getProposalsHistory() { + @External(readonly = true) + public Map getProposalsHistory(@Optional int startIndex) { List proposalKeys = new ArrayList<>(); - List> activeProposalsMap = new ArrayList<>(); + List> proposalHistory = new ArrayList<>(); List completedProjects = getProposalsKeysByStatus(COMPLETED); proposalKeys.addAll(completedProjects); @@ -2321,11 +2311,17 @@ public List> getProposalsHistory() { List disqualifiedProjects = getProposalsKeysByStatus(DISQUALIFIED); proposalKeys.addAll(disqualifiedProjects); - for (String proposal : proposalKeys) { - Map proposalDetails = getProposalDetails(proposal); - activeProposalsMap.add(proposalDetails); + int endIndex = startIndex + 10; + int size = proposalKeys.size(); + if (endIndex > size){ + endIndex = size; + } + + for (int i = startIndex; i < endIndex; i++) { + Map proposalDetails = getProposalDetails(proposalKeys.get(i)); + proposalHistory.add(proposalDetails); } - return activeProposalsMap; + return Map.of(DATA, proposalHistory, COUNT, size); } @@ -2402,10 +2398,6 @@ public void callScore(BigInteger amount, Address address, String method, Object. Context.call(amount, address, method, params); } - private void logger(String msg) { - Context.println(msg); - } - @External public void migrateProposals() { validateAdmins(); @@ -2438,20 +2430,4 @@ public void migrateProposals() { batchSize.set(endIndex); } } - @External(readonly = true) - public List getSponsorProjects(Address sponsor) { - return arrayDBtoList(sponsorProjects.at(sponsor)); - } - - @External(readonly = true) - public int getBatchSize() { - return batchSize.get(); - } - - @External - public void setBatchSize(){ - validateAdmins(); - batchSize.set(0); - } - } \ No newline at end of file From 3d95b39d0d81429ca22f3fdcfdd6aac262f802ca Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Mon, 28 Nov 2022 22:15:44 +0545 Subject: [PATCH 104/112] cleanup codes --- .../icon/cps/score/cpscore/CPSCore.java | 73 +++++++------------ .../icon/cps/score/cpscore/CPSScoreTest.java | 50 +++---------- CPSTreasury/build.gradle | 16 ++-- .../score/cpstreasury/CPSTreasuryTest.java | 18 ++--- .../lib/interfaces/CPSCoreInterface.java | 15 ++-- 5 files changed, 60 insertions(+), 112 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index e93b46bc..02df9eeb 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -5,28 +5,25 @@ import community.icon.cps.score.cpscore.db.ProgressReportDataDb; import community.icon.cps.score.cpscore.db.ProposalDataDb; import community.icon.cps.score.cpscore.utils.ArrayDBUtils; +import community.icon.cps.score.cpscore.utils.Migration; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface; import score.*; import score.annotation.EventLog; import score.annotation.External; import score.annotation.Optional; import score.annotation.Payable; +import scorex.util.ArrayList; import scorex.util.HashMap; import java.math.BigInteger; - -import scorex.util.ArrayList; - import java.util.List; import java.util.Map; import static community.icon.cps.score.cpscore.db.ProgressReportDataDb.*; import static community.icon.cps.score.cpscore.db.ProposalDataDb.*; -import static community.icon.cps.score.cpscore.utils.Constants.*; -import static community.icon.cps.score.cpscore.utils.Checkers.*; import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; - -import community.icon.cps.score.lib.interfaces.CPSCoreInterface; -import community.icon.cps.score.cpscore.utils.Migration; +import static community.icon.cps.score.cpscore.utils.Checkers.*; +import static community.icon.cps.score.cpscore.utils.Constants.*; public class CPSCore implements CPSCoreInterface { @@ -163,6 +160,7 @@ public Address getCpfTreasuryScore() { } + @Override @External public void setBnusdScore(Address score) { validateAdminScore(score); @@ -170,19 +168,14 @@ public void setBnusdScore(Address score) { setterGetter.balancedDollar.set(score); } - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void set_bnUSD_score(Address _score) { - setBnusdScore(_score); - } + @Override @External(readonly = true) public Address getBnusdScore() { SetterGetter setterGetter = new SetterGetter(); return setterGetter.balancedDollar.get(); } - @Override @Deprecated(since = "JAVA translation", forRemoval = true) @External(readonly = true) public Address get_bnUSD_score() { @@ -499,6 +492,7 @@ public void votePriority(String[] _proposals) { PriorityVote(caller, "Priority voting done successfully."); } + @Override @External public void setPrepPenaltyAmount(BigInteger[] penalty) { checkMaintenance(); @@ -513,7 +507,7 @@ public void setPrepPenaltyAmount(BigInteger[] penalty) { } - @Override + @Deprecated(since = "JAVA translation", forRemoval = true) @External public void set_prep_penalty_amount(BigInteger[] _penalty) { @@ -521,6 +515,7 @@ public void set_prep_penalty_amount(BigInteger[] _penalty) { } + @Override @External public void setInitialBlock() { validateAdmins(); @@ -532,13 +527,6 @@ public void setInitialBlock() { period.previousPeriodName.set("None"); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void set_initialBlock() { - setInitialBlock(); - } - @External(readonly = true) public Map loginPrep(Address address) { Map loginData = new HashMap<>(); @@ -605,6 +593,7 @@ public List
get_admins() { return getAdmins(); } + @Override @External(readonly = true) public Map getRemainingFund() { SetterGetter setterGetter = new SetterGetter(); @@ -612,7 +601,7 @@ public Map getRemainingFund() { return callScore(Map.class, setterGetter.cpfScore.get(), "get_total_funds"); } - @Override + @Deprecated(since = "JAVA translation", forRemoval = true) @External(readonly = true) public Map get_remaining_fund() { @@ -683,13 +672,7 @@ public List
get_denylist() { @External(readonly = true) public List
getContributors() { - List
contributors = new ArrayList<>(); - PReps pReps = new PReps(); - for (int i = 0; i < this.contributors.size(); i++) { - contributors.add(this.contributors.get(i)); - - } - return contributors; + return ArrayDBUtils.arrayDBtoList(this.contributors); } @Override @@ -1292,8 +1275,7 @@ private void updateProgressReportResult() { PReps pReps = new PReps(); List
_main_preps_list = arrayDBtoList(pReps.validPreps); - for (int i = 0; i < waiting_progress_reports.size(); i++) { - String _reports = waiting_progress_reports.get(i); + for (String _reports : waiting_progress_reports) { Map _report_result = getProgressReportDetails(_reports); String _ipfs_hash = (String) _report_result.get(IPFS_HASH); @@ -1307,15 +1289,12 @@ private void updateProgressReportResult() { int _approved_reports_count = (int) _proposal_details.get(APPROVED_REPORTS); Address _sponsor_address = (Address) _proposal_details.get(SPONSOR_ADDRESS); Address _contributor_address = (Address) _proposal_details.get(CONTRIBUTOR_ADDRESS); - int _completed = (int) _proposal_details.get(PERCENTAGE_COMPLETED); boolean _budget_adjustment = (boolean) _report_result.get(BUDGET_ADJUSTMENT); BigInteger _sponsor_deposit_amount = (BigInteger) _proposal_details.get(SPONSOR_DEPOSIT_AMOUNT); String flag = (String) _proposal_details.get("token"); int _approve_voters = (int) _report_result.get(APPROVE_VOTERS); - int _reject_voters = (int) _report_result.get(REJECT_VOTERS); BigInteger _approved_votes = (BigInteger) _report_result.get(APPROVED_VOTES); - BigInteger _rejected_votes = (BigInteger) _report_result.get(REJECTED_VOTES); BigInteger _total_votes = (BigInteger) _report_result.get(TOTAL_VOTES); int _total_voters = (int) _report_result.get(TOTAL_VOTERS); @@ -1350,7 +1329,7 @@ private void updateProgressReportResult() { updateProposalStatus(_ipfs_hash, ACTIVE); } ProposalDataDb.approvedReports.at(proposal_prefix).set(_approved_reports_count); -// Request CPS Treasury to add some installment amount to the contributor address +// Request CPS Treasury to add some installments amount to the contributor address callScore(getCpsTreasuryScore(), "send_installment_to_contributor", _ipfs_hash); // Request CPS Treasury to add some sponsor reward amount to the sponsor address callScore(getCpsTreasuryScore(), "send_reward_to_sponsor", _ipfs_hash); @@ -1450,14 +1429,14 @@ private void updateBudgetAdjustments(String _budget_key) { // After the budget adjustment is approved, Request new added fund to CPF - callScore(get_cpf_treasury_score(), "update_proposal_fund", _ipfs_hash, token_flag, _additional_budget, _additional_duration); + callScore(getCpfTreasuryScore(), "update_proposal_fund", _ipfs_hash, token_flag, _additional_budget, _additional_duration); } else { budgetAdjustmentStatus.at(_prefix).set(REJECTED); } } private void updateProposalsResult() { - BigInteger distributionAmount = get_remaining_fund().get(bnUSD); + BigInteger distributionAmount = getRemainingFund().get(bnUSD); List proposals = sortPriorityProposals(); PReps pReps = new PReps(); @@ -1494,7 +1473,7 @@ private void updateProposalsResult() { sponsors.add(sponsorAddress); sponsorProjects.at(sponsorAddress).add(proposal); ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).set(BOND_APPROVED); - callScore(get_cpf_treasury_score(), "transfer_proposal_fund_to_cps_treasury", + callScore(getCpfTreasuryScore(), "transfer_proposal_fund_to_cps_treasury", proposal, projectDuration, sponsorAddress, contributorAddress, flag, totalBudget); distributionAmount = distributionAmount.subtract(totalBudget); @@ -1749,7 +1728,7 @@ public Map getSponsorsRequests(String status, Address sponsorAdd } List proposalKeys; List sponsorRequests = new ArrayList<>(); - String prefix = ""; + String prefix; if (status.equals(APPROVED)) { proposalKeys = arrayDBtoList(this.sponsorProjects.at(sponsorAddress)); @@ -2083,7 +2062,7 @@ private void payPrepPenalty(Address from, BigInteger _value) { @Override @External public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { - Context.require(Context.getCaller().equals(get_bnUSD_score()), TAG + " Only bnUSD token accepted."); + Context.require(Context.getCaller().equals(getBnusdScore()), TAG + " Only bnUSD token accepted."); String unpacked_data = new String(_data); JsonObject transferData = Json.parse(unpacked_data).asObject(); @@ -2185,7 +2164,7 @@ public void claimSponsorBond() { } else if (amountBNUsd.compareTo(BigInteger.ZERO) > 0) { userAmounts.set(bnUSD, BigInteger.ZERO); - callScore(get_bnUSD_score(), "transfer", caller, amountBNUsd); + callScore(getBnusdScore(), "transfer", caller, amountBNUsd); SponsorBondClaimed(caller, amountIcx, amountBNUsd + " " + bnUSD + " withdrawn to " + caller); } else { Context.revert(TAG + " Claim Reward Fails. Available Amounts are " + amountIcx + " " + ICX + " and" + amountBNUsd + " " + bnUSD); @@ -2204,7 +2183,7 @@ private void swapBNUsdToken() { BigInteger currentBlock = BigInteger.valueOf(Context.getBlockHeight()); if (sbh.compareTo(currentBlock) < 0) { swapBlockHeight.set(currentBlock.add(SWAP_BLOCK_DIFF)); - callScore(get_cpf_treasury_score(), "swap_tokens", swapCount.getOrDefault(0)); + callScore(getCpfTreasuryScore(), "swap_tokens", swapCount.getOrDefault(0)); } } @@ -2245,8 +2224,8 @@ private void disqualifyProject(Address sponsorAddress, BigInteger sponsorDeposit JsonObject params = new JsonObject(); params.add(SPONSOR_ADDRESS, sponsorAddress.toString()); disqualifyProject.add("params", params); - Address cpfScore = get_cpf_treasury_score(); - callScore(get_bnUSD_score(), "transfer", cpfScore, + Address cpfScore = getCpfTreasuryScore(); + callScore(getBnusdScore(), "transfer", cpfScore, sponsorDepositAmount, disqualifyProject.toString().getBytes()); SponsorBondReturned(cpfScore, "Project Disqualified. " + sponsorDepositAmount + " " + flag + " returned to CPF Treasury Address."); @@ -2264,7 +2243,7 @@ public Map getActiveProposals(@Optional int startIndex) { int endIndex = startIndex + 10; int size = proposalKeys.size(); - if (endIndex > size){ + if (endIndex > size) { endIndex = size; } @@ -2313,7 +2292,7 @@ public Map getProposalsHistory(@Optional int startIndex) { int endIndex = startIndex + 10; int size = proposalKeys.size(); - if (endIndex > size){ + if (endIndex > size) { endIndex = size; } diff --git a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java index 1c02941d..90daab31 100644 --- a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java +++ b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java @@ -1,64 +1,37 @@ package community.icon.cps.score.cpscore; -import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; -import com.eclipsesource.json.JsonValue; import com.iconloop.score.test.Account; import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; import com.iconloop.score.test.TestBase; -import com.sun.management.DiagnosticCommandMBean; -import community.icon.cps.score.cpscore.utils.ArrayDBUtils; import community.icon.cps.score.cpscore.utils.Constants; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.junit.jupiter.api.function.Executable; -import org.mockito.Mock; -import org.mockito.stubbing.Answer; -import score.Address; import org.mockito.MockedStatic; import org.mockito.Mockito; - -import static community.icon.cps.score.cpscore.db.ProposalDataDb.rejectVoters; -import static community.icon.cps.score.cpscore.db.ProposalDataDb.sponsorAddress; -import static org.mockito.Mockito.*; - +import org.mockito.stubbing.Answer; +import score.Address; import score.ArrayDB; import score.Context; -import score.VarDB; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import java.math.BigInteger; -import java.nio.channels.MulticastChannel; -import java.security.SecureRandom; -import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.function.Function; import static community.icon.cps.score.cpscore.utils.Constants.*; -import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; +import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; public class CPSScoreTest extends TestBase{ - private static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); public static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000"); private static final Address cpsTreasury = Address.fromString("cx0000000000000000000000000000000000000002"); private static final Address cpfTreasury = Address.fromString("cx0000000000000000000000000000000000000003"); private static final Address bnUSDScore = Address.fromString("cx0000000000000000000000000000000000000004"); - private static final Address dividends = Address.fromString("cx0000000000000000000000000000000000000005"); - private static final Address utap = Address.fromString("cx0000000000000000000000000000000000000006"); - private static final Address rewards = Address.fromString("cx0000000000000000000000000000000000000006"); - - private static final Address dice = Address.fromString("cx0000000000000000000000000000000000000007"); - private static final Address roulette = Address.fromString("cx0000000000000000000000000000000000000008"); - private static final Address blackjack = Address.fromString("cx0000000000000000000000000000000000000009"); public static final String TAG = "CPS Score"; public static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); @@ -71,10 +44,7 @@ public class CPSScoreTest extends TestBase{ private static final Account testingAccount4 = sm.createAccount(); private static final Account testingAccount5 = sm.createAccount(); private static final Account testingAccount6 = sm.createAccount(); - private static final Account notRevshareWallet = sm.createAccount(); - public static final BigInteger decimal = new BigInteger("1000000000000000000"); private Score cpsScore; - private final SecureRandom secureRandom = new SecureRandom(); private static MockedStatic contextMock; CPSCore scoreSpy; @@ -1131,8 +1101,8 @@ void setCpfTreasury(){ void setbnUSDScore(){ addAdminMethod(); contextMock.when(caller()).thenReturn(owner.getAddress()); - cpsScore.invoke(owner, "set_bnUSD_score", bnUSDScore); - assertEquals(bnUSDScore, cpsScore.call("get_bnUSD_score")); + cpsScore.invoke(owner, "setBnusdScore", bnUSDScore); + assertEquals(bnUSDScore, cpsScore.call("getBnusdScore")); } @Test diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index 1e595c31..0fd824d8 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -1,17 +1,17 @@ version = '0.9.1' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.1' + compileOnly 'foundation.icon:javaee-api:0.9.2' implementation project(':score-lib') - implementation 'com.github.sink772:minimal-json:0.9.6' - implementation 'foundation.icon:javaee-scorex:0.5.2' + implementation 'com.github.sink772:minimal-json:0.9.7' + implementation 'foundation.icon:javaee-scorex:0.5.3' testImplementation project(':test-lib') - testImplementation 'foundation.icon:javaee-unittest:0.9.2' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation('org.mockito:mockito-inline:4.3.1') - intTestImplementation "foundation.icon:icon-sdk:2.1.0" + testImplementation 'foundation.icon:javaee-unittest:0.9.7' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + testImplementation('org.mockito:mockito-inline:4.8.0') + intTestImplementation 'foundation.icon:icon-sdk:2.2.0' intTestImplementation project(":score-client") intTestAnnotationProcessor project(":score-client") } diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index b3f399bd..dc4b17e3 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -95,7 +95,7 @@ void setCpsScore() { } private void setCpsScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); assertEquals(score_address, tokenScore.call("getCpsScore")); } @@ -106,7 +106,7 @@ void setCPFTreasuryScore() { } private void setCPFTreasuryScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpfTreasuryScore", cpfTreasury); assertEquals(cpfTreasury, tokenScore.call("getCpfTreasuryScore")); } @@ -117,23 +117,23 @@ void setBnUSDScore() { } private void setBnUSDScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setBnUSDScore", bnUSDScore); assertEquals(bnUSDScore, tokenScore.call("getBnUSDScore")); } - void setCpsScoreExceptions(Boolean isAdmin, Address score_address) { - doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); + void setCpsScoreExceptions(Boolean is_admin, Address score_address) { + doReturn(is_admin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); } - void setCpfTreasuryScoreExceptions(Boolean isAdmin, Address score_address) { - doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); + void setCpfTreasuryScoreExceptions(Boolean is_admin, Address score_address) { + doReturn(is_admin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpfTreasuryScore", score_address); } - void setBnUSDScoreExceptions(Boolean isAdmin, Address score_address) { - doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); + void setBnUSDScoreExceptions(Boolean is_admin, Address score_address) { + doReturn(is_admin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setBnUSDScore", score_address); } diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java index 4aead781..38d1c867 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java @@ -1,5 +1,7 @@ package community.icon.cps.score.lib.interfaces; +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; import score.Address; import score.annotation.EventLog; import score.annotation.External; @@ -10,9 +12,6 @@ import java.util.List; import java.util.Map; -import foundation.icon.score.client.ScoreClient; -import foundation.icon.score.client.ScoreInterface; - @ScoreClient @ScoreInterface public interface CPSCoreInterface { @@ -74,11 +73,11 @@ public static class ProgressReportAttributes { @External - void set_bnUSD_score(Address _score); + void setBnusdScore(Address _score); @External(readonly = true) - Address get_bnUSD_score(); + Address getBnusdScore(); @External(readonly = true) @@ -130,11 +129,11 @@ public static class ProgressReportAttributes { @External - void set_prep_penalty_amount(BigInteger[] _penalty); + void setPrepPenaltyAmount(BigInteger[] penalty); @External - void set_initialBlock(); + void setInitialBlock(); @External(readonly = true) @@ -147,7 +146,7 @@ public static class ProgressReportAttributes { @SuppressWarnings("unchecked") @External(readonly = true) - Map get_remaining_fund(); + Map getRemainingFund(); @External(readonly = true) From 6de73c7362f33dca8b64bfec3e93ac011d2bb12f Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Mon, 28 Nov 2022 22:18:58 +0545 Subject: [PATCH 105/112] remove completed todos --- .../src/main/java/community/icon/cps/score/cpscore/CPSCore.java | 1 - 1 file changed, 1 deletion(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 02df9eeb..c74871ed 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -316,7 +316,6 @@ public void unregister_prep() { @External public void registerPrep() { -// todo: check PRep list for candidate PRep after snapshot checkMaintenance(); updatePeriod(); Address caller = Context.getCaller(); From 8e6d12392ac7c8c2fae45a80910f8b643a260fbc Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Tue, 29 Nov 2022 02:13:57 +0545 Subject: [PATCH 106/112] add `getActiveProposals` add remaining methods --- .../icon/cps/score/cpscore/CPSCore.java | 59 ++++++++++++++++--- .../lib/interfaces/CPSCoreInterface.java | 2 +- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index c74871ed..400c9bb8 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -853,7 +853,10 @@ public void migrateAbstainVotes(Migration[] migrations) { for (Migration migration : migrations) { String proposalPrefix = proposalPrefix(migration.ipfsHash); for (int j = 0; j < migration.abstainVoters.length; j++) { - abstainVoters.at(proposalPrefix).add(migration.abstainVoters[j]); + Address voter = migration.abstainVoters[j]; + if (!ArrayDBUtils.containsInArrayDb(voter, abstainVoters.at(proposalPrefix))) { + abstainVoters.at(proposalPrefix).add(migration.abstainVoters[j]); + } } abstainedVotes.at(proposalPrefix).set(migration.abstainVotes); } @@ -1094,7 +1097,7 @@ public int check_change_vote(Address _address, String _ipfs_hash, String _propos } @External(readonly = true) - public Map>> getProjectAmounts() { + public Map getProjectAmounts() { List statusList = List.of(PENDING, ACTIVE, PAUSED, COMPLETED, DISQUALIFIED); BigInteger pendingAmountIcx = BigInteger.ZERO; BigInteger activeAmountIcx = BigInteger.ZERO; @@ -1142,11 +1145,11 @@ public Map>> getProjectAmounts() { } - return Map.of(statusList.get(0), Map.of(AMOUNT, Map.of(ICX, pendingAmountIcx, bnUSD, pendingAmountBnusd)), - statusList.get(1), Map.of(AMOUNT, Map.of(ICX, activeAmountIcx, bnUSD, activeAmountBnusd)), - statusList.get(2), Map.of(AMOUNT, Map.of(ICX, pausedAmountIcx, bnUSD, pausedAmountBnusd)), - statusList.get(3), Map.of(AMOUNT, Map.of(ICX, completedAmountIcx, bnUSD, completedAmountBnusd)), - statusList.get(4), Map.of(AMOUNT, Map.of(ICX, disqualifiedAmountIcx, bnUSD, disqualifiedAmountBnusd))); + return Map.of(statusList.get(0), Map.of(AMOUNT, Map.of(ICX, pendingAmountIcx, bnUSD, pendingAmountBnusd), "_count", proposalStatus.get(statusList.get(0)).size()), + statusList.get(1), Map.of(AMOUNT, Map.of(ICX, activeAmountIcx, bnUSD, activeAmountBnusd), "_count", proposalStatus.get(statusList.get(1)).size()), + statusList.get(2), Map.of(AMOUNT, Map.of(ICX, pausedAmountIcx, bnUSD, pausedAmountBnusd), "_count", proposalStatus.get(statusList.get(2)).size()), + statusList.get(3), Map.of(AMOUNT, Map.of(ICX, completedAmountIcx, bnUSD, completedAmountBnusd), "_count", proposalStatus.get(statusList.get(3)).size()), + statusList.get(4), Map.of(AMOUNT, Map.of(ICX, disqualifiedAmountIcx, bnUSD, disqualifiedAmountBnusd), "_count", proposalStatus.get(statusList.get(4)).size())); } @@ -1154,7 +1157,7 @@ public Map>> getProjectAmounts() { @Override @Deprecated(since = "JAVA translation", forRemoval = true) @External(readonly = true) - public Map>> get_project_amounts() { + public Map get_project_amounts() { return getProjectAmounts(); } @@ -2231,7 +2234,7 @@ private void disqualifyProject(Address sponsorAddress, BigInteger sponsorDeposit } @External(readonly = true) - public Map getActiveProposals(@Optional int startIndex) { + public Map getActiveProposalsList(@Optional int startIndex) { List proposalKeys = new ArrayList<>(); List> activeProposalsList = new ArrayList<>(); @@ -2253,6 +2256,44 @@ public Map getActiveProposals(@Optional int startIndex) { return Map.of(DATA, activeProposalsList, COUNT, size); } + /*** + Returns the list of all all active or paused proposal from that address + :param walletAddress : wallet address of the contributor + :type walletAddress: Address + :return: list of active proposals of a contributor + ***/ + @External(readonly = true) + public List> getActiveProposals(Address walletAddress) { + List> _proposal_titles = new ArrayList<>(); + + ArrayDB contributorsAddress = contributorProjects.at(walletAddress); + for (int i = 0; i < contributorsAddress.size(); i++) { + String proposals = contributorsAddress.get(i); + String prefix = proposalPrefix(proposals); + String status = ProposalDataDb.status.at(prefix).getOrDefault(""); + if (ArrayDBUtils.containsInList(status, List.of(ACTIVE, PAUSED))) { + int _project_duration = projectDuration.at(prefix).getOrDefault(0); + int _approved_reports_count = approvedReports.at(prefix).getOrDefault(0); + boolean _last_progress_report = _project_duration - _approved_reports_count == 1; + Map _proposals_details = Map.of(PROJECT_TITLE, projectTitle.at(prefix).getOrDefault(""), + IPFS_HASH, proposals, + NEW_PROGRESS_REPORT, submitProgressReport.at(prefix).getOrDefault(false), + "last_progress_report", _last_progress_report); + _proposal_titles.add(_proposals_details); + } + } + + return _proposal_titles; + } + + @Deprecated(since = "JAVA translation", forRemoval = true) + @External(readonly = true) + public List> get_active_proposals(Address _wallet_address) { + return getActiveProposals(_wallet_address); + } + + + /*** Returns a dict of proposals of provided status :param walletAddress : user Signing in diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java index 38d1c867..57246292 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java @@ -261,7 +261,7 @@ public static class ProgressReportAttributes { @External(readonly = true) - Map getActiveProposals(@Optional int startIndex); + Map getActiveProposalsList(@Optional int startIndex); @External(readonly = true) Map get_proposal_detail_by_wallet(Address _wallet_address); From 534b7203f91742f712acec852dc092ed05e8fa96 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Thu, 1 Dec 2022 00:25:12 +0545 Subject: [PATCH 107/112] move validateAdmins method to root file --- .../icon/cps/score/cpscore/utils/Checkers.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Checkers.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Checkers.java index 5a68a383..8f82c211 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Checkers.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Checkers.java @@ -1,12 +1,9 @@ package community.icon.cps.score.cpscore.utils; +import community.icon.cps.score.cpscore.SetterGetter; import score.Address; import score.Context; -import static community.icon.cps.score.cpscore.utils.Constants.TAG; -import community.icon.cps.score.cpscore.SetterGetter; -import community.icon.cps.score.cpscore.CPSCore; - public class Checkers { public static void onlyOwner() { Address caller = Context.getCaller(); @@ -14,18 +11,6 @@ public static void onlyOwner() { Context.require(caller.equals(owner), "SenderNotScoreOwner: Sender=" + caller + " Owner=" + owner); } - public static void validateAdmins() { - CPSCore cpsCore = new CPSCore(); - Context.require(cpsCore.isAdmin(Context.getCaller()), - TAG + ": Only Admins can call this method"); - - } - - public static void validateAdminScore(Address scoreAddress) { - validateAdmins(); - Context.require(scoreAddress.isContract(), scoreAddress + " is not a SCORE Address"); - - } public static void checkMaintenance() { SetterGetter setterGetter = new SetterGetter(); From 881712ec3636fefb49a7d200eaf32de5a82bbbcb Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Thu, 1 Dec 2022 00:26:46 +0545 Subject: [PATCH 108/112] - remove `percentageCompleted` from ProgressReportDataDb and used from ProposalDataDb - Remove sponsorVoteReason from getMethod to optimize the size on readonly --- .../icon/cps/score/cpscore/db/ProgressReportDataDb.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java index 27d0bc4b..0640ccd1 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java @@ -3,24 +3,22 @@ import score.*; import java.math.BigInteger; -import scorex.util.HashMap; import java.util.Map; +import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.recordTxHash; import static community.icon.cps.score.cpscore.utils.Constants.*; -import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; public class ProgressReportDataDb { private static final BranchDB> ipfsHash = Context.newBranchDB(IPFS_HASH, String.class); private static final BranchDB> reportHash = Context.newBranchDB(REPORT_HASH, String.class); private static final BranchDB> progressReportTitle = Context.newBranchDB(PROGRESS_REPORT_TITLE, String.class); - private static final BranchDB> timestamp = Context.newBranchDB(TIMESTAMP, BigInteger.class); + public static final BranchDB> timestamp = Context.newBranchDB(TIMESTAMP, BigInteger.class); public static final BranchDB> status = Context.newBranchDB(STATUS, String.class); private static final BranchDB> txHash = Context.newBranchDB(TX_HASH, String.class); private static final BranchDB> budgetAdjustment = Context.newBranchDB(BUDGET_ADJUSTMENT, Boolean.class); private static final BranchDB> additionalBudget = Context.newBranchDB(ADDITIONAL_BUDGET, BigInteger.class); private static final BranchDB> additionalMonth = Context.newBranchDB(ADDITIONAL_DURATION, Integer.class); - private static final BranchDB> percentageCompleted = Context.newBranchDB(PERCENTAGE_COMPLETED, Integer.class); public static final BranchDB> votersReasons = Context.newBranchDB(VOTERS_REASON, String.class); public static final BranchDB> totalVotes = Context.newBranchDB(TOTAL_VOTES, BigInteger.class); @@ -47,7 +45,6 @@ public static void addDataToProgressReportDB(ProgressReportAttributes progressDa timestamp.at(prefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); additionalBudget.at(prefix).set(progressData.additional_budget.multiply(EXA)); additionalMonth.at(prefix).set(progressData.additional_month); - percentageCompleted.at(prefix).set(progressData.percentage_completed); status.at(prefix).set(WAITING); txHash.at(prefix).set(recordTxHash(Context.getTransactionHash())); budgetAdjustment.at(prefix).set(progressData.budget_adjustment); @@ -84,7 +81,6 @@ public static Map getDataFromProgressReportDB(String prefix) { Map.entry(BUDGET_REJECT_VOTERS, budgetRejectVoters.at(prefix).size()), Map.entry(BUDGET_ADJUSTMENT_STATUS, budgetAdjustmentStatus.at(prefix).getOrDefault("")), Map.entry(IPFS_LINK, ipfsLink.at(prefix).getOrDefault("")), - Map.entry(PERCENTAGE_COMPLETED, percentageCompleted.at(prefix).getOrDefault(0)), Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false)), Map.entry(PROJECT_TITLE, ProposalDataDb.projectTitle.at(proposalPrefix(proposalHash)).getOrDefault("")), Map.entry(CONTRIBUTOR_ADDRESS, ProposalDataDb.contributorAddress.at(proposalPrefix(proposalHash)).get())); From a8290486d02839242671062bff09a62793248025 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Thu, 1 Dec 2022 00:26:54 +0545 Subject: [PATCH 109/112] - remove `percentageCompleted` from ProgressReportDataDb and used from ProposalDataDb - Remove sponsorVoteReason from getMethod to optimize the size on readonly --- .../community/icon/cps/score/cpscore/db/ProposalDataDb.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java index f1afa1aa..9425118b 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java @@ -3,10 +3,9 @@ import score.*; import java.math.BigInteger; -import scorex.util.HashMap; import java.util.Map; -import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; +import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.recordTxHash; import static community.icon.cps.score.cpscore.utils.Constants.*; import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; @@ -23,7 +22,7 @@ public class ProposalDataDb { public static final BranchDB> ipfsLink = Context.newBranchDB(IPFS_LINK, String.class); public static final BranchDB> status = Context.newBranchDB(STATUS, String.class); private static final BranchDB> txHash = Context.newBranchDB(TX_HASH, String.class); - private static final BranchDB> percentageCompleted = Context.newBranchDB(PERCENTAGE_COMPLETED, Integer.class); + public static final BranchDB> percentageCompleted = Context.newBranchDB(PERCENTAGE_COMPLETED, Integer.class); public static final BranchDB> votersReasons = Context.newBranchDB(VOTERS_REASON, String.class); public static final BranchDB> totalVotes = Context.newBranchDB(TOTAL_VOTES, BigInteger.class); public static final BranchDB> totalVoters = Context.newBranchDB(TOTAL_VOTERS, Integer.class); @@ -94,7 +93,6 @@ public static Map getDataFromProposalDB(String prefix) { Map.entry(SPONSOR_DEPOSIT_AMOUNT, sponsorDepositAmount.at(prefix).getOrDefault(BigInteger.ZERO)), Map.entry(SPONSORED_TIMESTAMP, sponsoredTimestamp.at(prefix).getOrDefault(BigInteger.ZERO)), Map.entry(SPONSOR_DEPOSIT_STATUS, sponsorDepositStatus.at(prefix).getOrDefault("")), - Map.entry(SPONSOR_VOTE_REASON, reason), Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size()), Map.entry(ABSTAIN_VOTERS, abstainVoters.at(prefix).size()), From d984ee57bf9a4dd706929b5a953a4c4b4fd4f273 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Thu, 1 Dec 2022 00:27:26 +0545 Subject: [PATCH 110/112] - update CPSCore contract interfaces --- .../lib/interfaces/CPSCoreInterface.java | 90 +++++++++---------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java index 57246292..c029e777 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java @@ -36,6 +36,7 @@ public static class ProgressReportAttributes { public int additional_month; public int percentage_completed; } + @External(readonly = true) String name(); @@ -43,43 +44,43 @@ public static class ProgressReportAttributes { String progressReportPrefix(String progressKey); - + @External void set_cps_treasury_score(Address _score); @External void setCpsTreasuryScore(Address score); - + @External(readonly = true) Address get_cps_treasury_score(); @External(readonly = true) Address getCpsTreasuryScore(); - + @External void set_cpf_treasury_score(Address _score); @External void setCpfTreasuryScore(Address score); - + @External(readonly = true) Address get_cpf_treasury_score(); @External(readonly = true) Address getCpfTreasuryScore(); - + @External void setBnusdScore(Address _score); - + @External(readonly = true) Address getBnusdScore(); - + @External(readonly = true) boolean isAdmin(Address address); @@ -89,7 +90,7 @@ public static class ProgressReportAttributes { @External(readonly = true) boolean getBudgetAdjustmentFeature(); - + @External void toggleMaintenance(); @@ -99,19 +100,19 @@ public static class ProgressReportAttributes { @Payable void fallback(); - + @External void addAdmin(Address address); - + @External void removeAdmin(Address address); - + @External void unregister_prep(); - + @External void register_prep(); @@ -127,145 +128,138 @@ public static class ProgressReportAttributes { @External void votePriority(String[] proposals); - + @External void setPrepPenaltyAmount(BigInteger[] penalty); - + @External void setInitialBlock(); - + @External(readonly = true) Map login_prep(Address _address); - + @External(readonly = true) List
get_admins(); @SuppressWarnings("unchecked") - + @External(readonly = true) Map getRemainingFund(); - + @External(readonly = true) List> get_PReps(); - + @External(readonly = true) List
get_denylist(); - + @External(readonly = true) Map get_period_status(); - + @External(readonly = true) List
get_contributors(); - + @External(readonly = true) Map check_claimable_sponsor_bond(Address _address); - + @Payable @External void submit_proposal(ProposalAttributes _proposals); - + @External void vote_proposal(String _ipfs_key, String _vote, String _vote_reason, @Optional boolean _vote_change); - + @External void submit_progress_report(ProgressReportAttributes _progress_report); - + @External void vote_progress_report(String _ipfs_key, String _report_key, String _vote, String _vote_reason, @Optional String _budget_adjustment_vote, @Optional boolean _vote_change); - + @External(readonly = true) List get_proposals_keys_by_status(String _status); - + @External(readonly = true) int check_change_vote(Address _address, String _ipfs_hash, String _proposal_type); - + @External(readonly = true) Map get_project_amounts(); - + @External(readonly = true) Map get_sponsors_record(); @External void update_period(); - + @External(readonly = true) - Map get_proposal_details(String _status, @Optional Address _wallet_address, @Optional int _start_index, @Optional int _end_index); + Map getProposalDetails(String status, @Optional Address walletAddress, @Optional int startIndex); @External(readonly = true) Map get_proposal_details_by_hash(String _ipfs_key); - + @External(readonly = true) - Map get_progress_reports(String _status, @Optional int _start_index, @Optional int _end_index); + Map getProgressReports(String status, @Optional int startIndex); + - @External(readonly = true) Map get_progress_reports_by_hash(String _report_key); - + @External(readonly = true) Map get_progress_reports_by_proposal(String _ipfs_key); - + @External(readonly = true) - Map get_sponsors_requests(String _status, Address _sponsor_address, @Optional int _start_index, @Optional int _end_index); + Map getSponsorsRequests(String status, Address sponsorAddress, @Optional int startIndex); @External(readonly = true) - Map get_vote_result(String _ipfs_key); @External(readonly = true) - Map get_progress_report_result(String _report_key); @External(readonly = true) - Map get_budget_adjustment_vote_result(String _report_key); @External - void tokenFallback(Address _from, BigInteger _value, byte[] _data); @External - void remove_denylist_preps(); @External - void claim_sponsor_bond(); @External - void set_swap_count(int value); @External - void updateNextBlock(int blockCount); - + @External(readonly = true) Map getActiveProposalsList(@Optional int startIndex); @External(readonly = true) - Map get_proposal_detail_by_wallet(Address _wallet_address); + Map getProposalDetailByWallet(Address walletAddress, @Optional int startIndex); + @External(readonly = true) Map getProposalsHistory(@Optional int startIndex); // EventLogs From 44c27d16ad42e9c6b12147c24ff09c1583e067a8 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Thu, 1 Dec 2022 00:29:15 +0545 Subject: [PATCH 111/112] - add adminCheckers on root - Remove migration code --- .../icon/cps/score/cpscore/CPSCore.java | 40 +++++-------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index 400c9bb8..acbc8cfd 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -2417,36 +2417,16 @@ public void callScore(BigInteger amount, Address address, String method, Object. Context.call(amount, address, method, params); } - @External - public void migrateProposals() { + + public void validateAdmins() { + Context.require(isAdmin(Context.getCaller()), + TAG + ": Only Admins can call this method"); + + } + + public void validateAdminScore(Address scoreAddress) { validateAdmins(); - int startIndex = batchSize.get(); - int size = proposalsKeyList.size(); - int endIndex = startIndex + 10; - if (endIndex > size) { - endIndex = size; - } - List statusType = List.of(SPONSOR_PENDING, REJECTED, DISQUALIFIED, PENDING); - String status; - Address sponsor; - String prefix; - String ipfsKey; - Address contributor; - for (int i = startIndex; i < endIndex; i++) { - ipfsKey = proposalsKeyList.get(i); - prefix = proposalPrefix(ipfsKey); - sponsor = sponsorAddress.at(prefix).get(); - contributor = contributorAddress.at(prefix).get(); - status = ProposalDataDb.status.at(prefix).get(); - if (!ArrayDBUtils.containsInList(status, statusType)) { - if (!ArrayDBUtils.containsInArrayDb(ipfsKey, sponsorProjects.at(sponsor))) { - sponsorProjects.at(sponsor).add(ipfsKey); - } - } - if (!ArrayDBUtils.containsInArrayDb(ipfsKey, contributorProjects.at(contributor))) { - contributorProjects.at(contributor).add(ipfsKey); - } - batchSize.set(endIndex); - } + Context.require(scoreAddress.isContract(), scoreAddress + " is not a SCORE Address"); + } } \ No newline at end of file From 81415479ac68063f468bf8ae8d44795081a46fd6 Mon Sep 17 00:00:00 2001 From: sdp_ibriz Date: Thu, 1 Dec 2022 00:30:38 +0545 Subject: [PATCH 112/112] - Optimize Readonly methods - Set pagination to 10 elements - Reduce use of branchDBs' to optimize step uses - --- .../icon/cps/score/cpscore/CPSCore.java | 238 ++++++++---------- 1 file changed, 106 insertions(+), 132 deletions(-) diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java index acbc8cfd..c9bf3a7c 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java @@ -5,7 +5,6 @@ import community.icon.cps.score.cpscore.db.ProgressReportDataDb; import community.icon.cps.score.cpscore.db.ProposalDataDb; import community.icon.cps.score.cpscore.utils.ArrayDBUtils; -import community.icon.cps.score.cpscore.utils.Migration; import community.icon.cps.score.lib.interfaces.CPSCoreInterface; import score.*; import score.annotation.EventLog; @@ -22,7 +21,8 @@ import static community.icon.cps.score.cpscore.db.ProgressReportDataDb.*; import static community.icon.cps.score.cpscore.db.ProposalDataDb.*; import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; -import static community.icon.cps.score.cpscore.utils.Checkers.*; +import static community.icon.cps.score.cpscore.utils.Checkers.checkMaintenance; +import static community.icon.cps.score.cpscore.utils.Checkers.onlyOwner; import static community.icon.cps.score.cpscore.utils.Constants.*; public class CPSCore implements CPSCoreInterface { @@ -72,12 +72,9 @@ public class CPSCore implements CPSCoreInterface { private final ArrayDB
priorityVotedPreps = Context.newArrayDB(PRIORITY_VOTED_PREPS, Address.class); private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS, String.class); private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS, String.class); - private final VarDB batchSize = Context.newVarDB(BATCH_SIZE, Integer.class); public CPSCore() { PeriodController periodController = new PeriodController(); - periodController.periodCount.set(20); - batchSize.set(0); } @Override @@ -186,7 +183,7 @@ private boolean proposalKeyExists(String key) { return proposalsKeyListIndex.get(key) != null; } - private boolean _progress_key_exists(String key) { + private boolean progressKeyExists(String key) { return progressKeyListIndex.get(key) != null; } @@ -213,7 +210,7 @@ public void toggleBudgetAdjustmentFeature() { @External(readonly = true) public boolean getBudgetAdjustmentFeature() { SetterGetter setterGetter = new SetterGetter(); - return setterGetter.budgetAdjustment.get(); + return setterGetter.budgetAdjustment.getOrDefault(true); } @External @@ -265,7 +262,7 @@ private void burn(BigInteger amount, @Optional Address token) { @External(readonly = true) public int getPeriodCount() { PeriodController periodController = new PeriodController(); - return periodController.periodCount.get(); + return periodController.periodCount.getOrDefault(0); } @External @@ -441,8 +438,8 @@ private BigInteger getPenaltyAmount(Address address) { @Override @External(readonly = true) - public boolean checkPriorityVoting(Address prep) { - return ArrayDBUtils.containsInArrayDb(prep, priorityVotedPreps); + public boolean checkPriorityVoting(Address _prep) { + return ArrayDBUtils.containsInArrayDb(_prep, priorityVotedPreps); } @Override @@ -463,7 +460,7 @@ public Map getPriorityVoteResult() { for (int i = 0; i < pending.size(); i++) { String prop = pending.get(i); - priorityVoteResult.put(prop, proposalRank.get(prop)); + priorityVoteResult.put(prop, proposalRank.getOrDefault(prop, 0)); } return priorityVoteResult; @@ -576,12 +573,7 @@ public Map login_prep(Address _address) { @External(readonly = true) public List
getAdmins() { - List
adminList = new ArrayList<>(); - for (int i = 0; i < admins.size(); i++) { - adminList.add(admins.get(i)); - - } - return adminList; + return ArrayDBUtils.arrayDBtoList(admins); } @@ -845,23 +837,6 @@ public void vote_proposal(String _ipfs_key, String _vote, String _vote_reason, @ voteProposal(_ipfs_key, _vote, _vote_reason, _vote_change); } - @External - public void migrateAbstainVotes(Migration[] migrations) { - validateAdmins(); - Context.require(migrations.length <= MIGRATION_BATCH, TAG + ": The length of data should be " + - "smaller than or equal to " + MIGRATION_BATCH); - for (Migration migration : migrations) { - String proposalPrefix = proposalPrefix(migration.ipfsHash); - for (int j = 0; j < migration.abstainVoters.length; j++) { - Address voter = migration.abstainVoters[j]; - if (!ArrayDBUtils.containsInArrayDb(voter, abstainVoters.at(proposalPrefix))) { - abstainVoters.at(proposalPrefix).add(migration.abstainVoters[j]); - } - } - abstainedVotes.at(proposalPrefix).set(migration.abstainVotes); - } - } - @External public void submitProgressReport(ProgressReportAttributes progressReport) { checkMaintenance(); @@ -890,15 +865,18 @@ public void submitProgressReport(ProgressReportAttributes progressReport) { String reportHash = progressReport.report_hash; String ipfsHash = progressReport.ipfs_hash; - Context.require(!_progress_key_exists(reportHash), TAG + ": Report key already exists."); + Context.require(!progressKeyExists(reportHash), TAG + ": Report key already exists."); Context.require(proposalKeyExists(ipfsHash), TAG + ": Invalid proposal key"); addNewProgressReportKey(ipfsHash, reportHash); String reportHashPrefix = progressReportPrefix(reportHash); addDataToProgressReportDB(progressReport, reportHashPrefix); int percentageCompleted = progressReport.percentage_completed; - Context.require(percentageCompleted >= 0 && percentageCompleted <= 100, - TAG + ": Percentage Completed must be between 0 and 100"); + if (percentageCompleted >= 0 && percentageCompleted <= 100) { + ProposalDataDb.percentageCompleted.at(ipfsHashPrefix).set(percentageCompleted); + } else { + Context.revert(TAG + ": Percentage completed should be between 0 and 100"); + } if (progressReport.budget_adjustment) { Context.require(getBudgetAdjustmentFeature(), @@ -1060,13 +1038,8 @@ public void vote_progress_report(String _ipfs_key, String _report_key, String _v @External(readonly = true) public List getProposalsKeysByStatus(String status) { Context.require(STATUS_TYPE.contains(status), TAG + ": Not a valid status"); - List proposalStatusList = new ArrayList<>(); - ArrayDB proposalStatus = this.proposalStatus.get(status); - for (int i = 0; i < proposalStatus.size(); i++) { - proposalStatusList.add(proposalStatus.get(i)); - } - return proposalStatusList; + return ArrayDBUtils.arrayDBtoList(proposalStatus); } @Override @@ -1157,7 +1130,7 @@ public Map getProjectAmounts() { @Override @Deprecated(since = "JAVA translation", forRemoval = true) @External(readonly = true) - public Map get_project_amounts() { + public Map get_project_amounts() { return getProjectAmounts(); } @@ -1527,7 +1500,7 @@ private void updateProposalsResult() { private void updateProposalStatus(String proposalHash, String propStatus) { String proposalPrefix = proposalPrefix(proposalHash); String currentStatus = ProposalDataDb.status.at(proposalPrefix).get(); - ProposalDataDb.timestamp.at(proposalPrefix).set(BigInteger.valueOf(Context.getBlockHeight())); + ProposalDataDb.timestamp.at(proposalPrefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); ProposalDataDb.status.at(proposalPrefix).set(propStatus); ArrayDB proposalStatus = this.proposalStatus.get(currentStatus); @@ -1538,8 +1511,8 @@ private void updateProposalStatus(String proposalHash, String propStatus) { private void updateProgressReportStatus(String progressHash, String progressStatus) { String progressPrefix = progressReportPrefix(progressHash); String currentStatus = ProgressReportDataDb.status.at(progressPrefix).get(); - ProposalDataDb.timestamp.at(progressPrefix).set(BigInteger.valueOf(Context.getBlockHeight())); - ProposalDataDb.status.at(progressPrefix).set(progressStatus); + ProgressReportDataDb.timestamp.at(progressPrefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); + ProgressReportDataDb.status.at(progressPrefix).set(progressStatus); ArrayDB progressReportStatus = this.progressReportStatus.get(currentStatus); ArrayDBUtils.removeArrayItem(progressReportStatus, progressHash); @@ -1557,8 +1530,11 @@ private void checkInactivePreps(ArrayDB
prepList) { } private Map getProposalDetails(String proposal) { - proposalKeyExists(proposal); - return getDataFromProposalDB(proposalPrefix(proposal)); + if (proposalKeyExists(proposal)) { + return getDataFromProposalDB(proposalPrefix(proposal)); + } + return Map.of(); + } private void addNewProgressReportKey(String ipfsHash, String reportHash) { @@ -1568,11 +1544,9 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash) { } } + @Override @External(readonly = true) - public Map getProposalDetails(String status, @Optional Address walletAddress, @Optional int startIndex, @Optional int endIndex) { - if (endIndex == 0) { - endIndex = 10; - } + public Map getProposalDetails(String status, @Optional Address walletAddress, @Optional int startIndex) { if (!STATUS_TYPE.contains(status)) { return Map.of(MESSAGE, "Not a valid _status."); } @@ -1582,9 +1556,7 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash) { if (startIndex < 0) { startIndex = 0; } - if ((endIndex - startIndex) > 10) { - return Map.of(MESSAGE, "Page length must not be greater than 10."); - } + int endIndex = startIndex + 10; int count = proposalKeys.size(); if (endIndex > count) { @@ -1606,20 +1578,23 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash) { } } - return Map.of(DATA, proposalsList, COUNT, proposalsList.size()); + return Map.of(DATA, proposalsList, COUNT, count); } - @Override @Deprecated(since = "JAVA translation", forRemoval = true) @External(readonly = true) - public Map get_proposal_details(String _status, @Optional Address _wallet_address, @Optional int _start_index, @Optional int _end_index) { - return getProposalDetails(_status, _wallet_address, _start_index, _end_index); + public Map get_proposal_details(String _status, @Optional Address _wallet_address, @Optional int _start_index) { + return getProposalDetails(_status, _wallet_address, _start_index); } @External(readonly = true) public Map getProposalDetailsByHash(String ipfsKey) { - return getProposalDetails(ipfsKey); + Map proposalDetails = new HashMap<>(); + String prefix = proposalPrefix(ipfsKey); + proposalDetails.putAll(getProposalDetails(ipfsKey)); + proposalDetails.put(SPONSOR_VOTE_REASON, ProposalDataDb.sponsorVoteReason.at(prefix).getOrDefault("")); + return proposalDetails; } @Override @@ -1633,11 +1608,9 @@ private Map getProgressReportDetails(String progressKey) { return getDataFromProgressReportDB(progressReportPrefix(progressKey)); } + @Override @External(readonly = true) - public Map getProgressReports(String status, @Optional int startIndex, @Optional int endIndex) { - if (endIndex == 0) { - endIndex = 10; - } + public Map getProgressReports(String status, @Optional int startIndex) { if (!PROGRESS_REPORT_STATUS_TYPE.contains(status)) { return Map.of(MESSAGE, "Not a valid _status."); } @@ -1648,11 +1621,9 @@ private Map getProgressReportDetails(String progressKey) { if (startIndex < 0) { startIndex = 0; } - if ((endIndex - startIndex) > 10) { - return Map.of(MESSAGE, "Page length must not be greater than 10."); - } - int count = progressReportKeys.size(); + int endIndex = startIndex + 10; + int count = progressReportKeys.size(); if (endIndex > count) { endIndex = count; } @@ -1669,11 +1640,10 @@ private Map getProgressReportDetails(String progressKey) { return Map.of(DATA, progressReportList, COUNT, progressReportList.size()); } - @Override @Deprecated(since = "JAVA translation", forRemoval = true) @External(readonly = true) - public Map get_progress_reports(String _status, @Optional int _start_index, @Optional int _end_index) { - return getProgressReports(_status, _start_index, _end_index); + public Map get_progress_reports(String _status, @Optional int _start_index) { + return getProgressReports(_status, _start_index); } /*** @@ -1685,11 +1655,12 @@ private Map getProgressReportDetails(String progressKey) { ***/ @External(readonly = true) public Map getProgressReportsByHash(String reportKey) { - if (!_progress_key_exists(reportKey)) { - return Map.of("message", TAG + ": Not a valid IPFS Hash for Progress Report"); + if (progressKeyExists(reportKey)) { + return getProgressReportDetails(reportKey); } + return Map.of(); + - return getProgressReportDetails(reportKey); } @Override @@ -1720,15 +1691,17 @@ public Map get_progress_reports_by_proposal(String _ipfs_key) { return getProgressReportsByProposal(_ipfs_key); } + @Override @External(readonly = true) - public Map getSponsorsRequests(String status, Address sponsorAddress, @Optional int startIndex, @Optional int endIndex) { - if (endIndex == 0) { - endIndex = 20; + public Map getSponsorsRequests(String status, Address sponsorAddress, @Optional int startIndex) { + if (startIndex < 0) { + startIndex = 0; } - if (!List.of(APPROVED, SPONSOR_PENDING, REJECTED, DISQUALIFIED).contains(status)) { + int endIndex = startIndex + 10; + if (!ArrayDBUtils.containsInList(status, List.of(APPROVED, SPONSOR_PENDING, REJECTED, DISQUALIFIED))) { return Map.of(MESSAGE, "Not a valid _status."); } - List proposalKeys; + List proposalKeys = new ArrayList<>(); List sponsorRequests = new ArrayList<>(); String prefix; @@ -1742,20 +1715,14 @@ public Map getSponsorsRequests(String status, Address sponsorAdd } } } else { - proposalKeys = getProposalsKeysByStatus(status); - for (String ipfsKey : proposalKeys) { + List proposalKeysList = getProposalsKeysByStatus(status); + for (String ipfsKey : proposalKeysList) { prefix = proposalPrefix(ipfsKey); if (ProposalDataDb.sponsorAddress.at(prefix).get().equals(sponsorAddress)) { proposalKeys.add(ipfsKey); } } } - if (startIndex < 0) { - startIndex = 0; - } - if ((endIndex - startIndex) > 50) { - return Map.of(MESSAGE, "Page length must not be greater than 50."); - } int count = proposalKeys.size(); if (endIndex > count) { endIndex = count; @@ -1767,8 +1734,9 @@ public Map getSponsorsRequests(String status, Address sponsorAdd String proposalKey = proposalKeys.get(i); String proposalPrefix = proposalPrefix(proposalKey); String sponsorDepositStatus = ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).getOrDefault(""); + Map proposalDetails = getProposalDetails(proposalKey); + sponsorRequests.add(proposalDetails); if (sponsorDepositStatus.equals(BOND_APPROVED)) { - Map proposalDetails = getProposalDetails(proposalKey); String token = (String) proposalDetails.get(TOKEN); BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); if (token.equals(ICX)) { @@ -1776,19 +1744,17 @@ public Map getSponsorsRequests(String status, Address sponsorAdd } else if (token.equals(bnUSD)) { sponsorAmountBnusd = sponsorAmountBnusd.add(sponsorDepositAmount); } - sponsorRequests.add(proposalDetails); } } - return Map.of(DATA, sponsorRequests, COUNT, sponsorRequests.size(), + return Map.of(DATA, sponsorRequests, COUNT, proposalKeys.size(), SPONSOR_DEPOSIT_AMOUNT, Map.of(ICX, sponsorAmountICX, bnUSD, sponsorAmountBnusd)); } - @Override @Deprecated(since = "JAVA translation", forRemoval = true) @External(readonly = true) - public Map get_sponsors_requests(String _status, Address _sponsor_address, @Optional int _start_index, @Optional int _end_index) { - return getSponsorsRequests(_status, _sponsor_address, _start_index, _end_index); + public Map get_sponsors_requests(String _status, Address _sponsor_address, @Optional int _start_index) { + return getSponsorsRequests(_status, _sponsor_address, _start_index); } /*** @@ -1844,19 +1810,25 @@ public Map getVoteResult(String ipfsKey) { String prefix = proposalPrefix(ipfsKey); ArrayDB
_voters_list = ProposalDataDb.votersList.at(prefix); - + ArrayDB
approve_voters = ProposalDataDb.approveVoters.at(prefix); + ArrayDB
reject_voters = ProposalDataDb.rejectVoters.at(prefix); List> _vote_status = new ArrayList<>(); String vote; for (int i = 0; i < _voters_list.size(); i++) { Address voter = _voters_list.get(i); - if ((int) votersListIndex.at(prefix).at(voter).getOrDefault(VOTE, NOT_VOTED) == APPROVE_) { + if (containsInArrayDb(voter, approve_voters)) { vote = APPROVE; - } else if ((int) votersListIndex.at(prefix).at(voter).getOrDefault(VOTE, NOT_VOTED) == REJECT_) { + } else if (containsInArrayDb(voter, reject_voters)) { vote = REJECT; } else { vote = ABSTAIN; } + String reason = ProposalDataDb.votersReasons.at(prefix).get(i); + if (reason == null) { + reason = ""; + } + Map _voters = Map.of(ADDRESS, voter, PREP_NAME, getPrepName(voter), @@ -1865,8 +1837,8 @@ PREP_NAME, getPrepName(voter), _vote_status.add(_voters); } - return Map.of(DATA, _vote_status, APPROVE_VOTERS, ProposalDataDb.approveVoters.at(prefix).size(), - REJECT_VOTERS, ProposalDataDb.rejectVoters.at(prefix).size(), + return Map.of(DATA, _vote_status, APPROVE_VOTERS, approve_voters.size(), + REJECT_VOTERS, reject_voters.size(), TOTAL_VOTERS, ProposalDataDb.totalVoters.at(prefix).getOrDefault(0), APPROVED_VOTES, ProposalDataDb.approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO), REJECTED_VOTES, ProposalDataDb.rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO), @@ -1889,27 +1861,28 @@ public Map get_vote_result(String _ipfs_key) { ***/ @External(readonly = true) public Map getProgressReportResult(String reportKey) { - Map _proposal_details = getProgressReportDetails(reportKey); String prefix = progressReportPrefix(reportKey); - List
_voters_list = arrayDBtoList(ProgressReportDataDb.votersList.at(prefix)); - List
_approved_voters_list = arrayDBtoList(ProgressReportDataDb.approveVoters.at(prefix)); - List
_rejected_voters_list = arrayDBtoList(ProgressReportDataDb.rejectVoters.at(prefix)); + ArrayDB
_voters_list = ProgressReportDataDb.votersList.at(prefix); + ArrayDB
_approved_voters_list = ProgressReportDataDb.approveVoters.at(prefix); + ArrayDB
_rejected_voters_list = ProgressReportDataDb.rejectVoters.at(prefix); List> _vote_status = new ArrayList<>(); String vote; // Differentiating the P-Rep(s) votes according to their votes for (int i = 0; i < _voters_list.size(); i++) { Address voter = _voters_list.get(i); - if (containsInList(voter, _approved_voters_list)) { + if (containsInArrayDb(voter, _approved_voters_list)) { vote = APPROVE; - } else if (containsInList(voter, _rejected_voters_list)) { + } else if (containsInArrayDb(voter, _rejected_voters_list)) { vote = REJECT; } else { vote = "not voted"; } String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); - + if (reason == null) { + reason = ""; + } Map _voters = Map.of(ADDRESS, voter, PREP_NAME, getPrepName(voter), VOTE_REASON, reason, @@ -1919,10 +1892,10 @@ PREP_NAME, getPrepName(voter), return Map.of(DATA, _vote_status, APPROVE_VOTERS, _approved_voters_list.size(), REJECT_VOTERS, _rejected_voters_list.size(), - TOTAL_VOTERS, _proposal_details.get(TOTAL_VOTERS), - APPROVED_VOTES, _proposal_details.get(APPROVED_VOTES), - REJECTED_VOTES, _proposal_details.get(REJECTED_VOTES), - TOTAL_VOTES, _proposal_details.get(TOTAL_VOTES)); + TOTAL_VOTERS, ProgressReportDataDb.totalVoters.at(prefix).getOrDefault(0), + APPROVED_VOTES, ProgressReportDataDb.approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO), + REJECTED_VOTES, ProgressReportDataDb.rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO), + TOTAL_VOTES, ProgressReportDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)); } @Override @@ -1942,38 +1915,35 @@ public Map get_progress_report_result(String _report_key) { @External(readonly = true) public Map getBudgetAdjustmentVoteResult(String reportKey) { - Map _proposal_details = getProgressReportDetails(reportKey); String prefix = progressReportPrefix(reportKey); - List
_voters_list = arrayDBtoList(ProgressReportDataDb.votersList.at(prefix)); - List
_approved_voters_list = arrayDBtoList(budgetApproveVoters.at(prefix)); - List
_rejected_voters_list = arrayDBtoList(budgetRejectVoters.at(prefix)); + ArrayDB
_voters_list = ProgressReportDataDb.votersList.at(prefix); + ArrayDB
_approved_voters_list = budgetApproveVoters.at(prefix); + ArrayDB
_rejected_voters_list = budgetRejectVoters.at(prefix); List> _vote_status = new ArrayList<>(); String vote; for (int i = 0; i < _voters_list.size(); i++) { Address voter = _voters_list.get(i); - if (containsInList(voter, _approved_voters_list)) { + if (containsInArrayDb(voter, _approved_voters_list)) { vote = APPROVE; - } else if (containsInList(voter, _rejected_voters_list)) { + } else if (containsInArrayDb(voter, _rejected_voters_list)) { vote = REJECT; } else { vote = "not voted"; } - String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); Map _voters = Map.of( ADDRESS, voter, PREP_NAME, getPrepName(voter), - VOTE_REASON, reason, VOTE, vote); _vote_status.add(_voters); } - return Map.of(DATA, _vote_status, APPROVE_VOTERS, _proposal_details.get(BUDGET_APPROVE_VOTERS), - REJECT_VOTERS, _proposal_details.get(BUDGET_REJECT_VOTERS), - TOTAL_VOTERS, _proposal_details.get(TOTAL_VOTERS), - APPROVED_VOTES, _proposal_details.get(BUDGET_APPROVED_VOTES), - REJECTED_VOTES, _proposal_details.get(BUDGET_REJECTED_VOTES), - TOTAL_VOTES, _proposal_details.get(TOTAL_VOTES)); + return Map.of(DATA, _vote_status, APPROVE_VOTERS, _approved_voters_list.size(), + REJECT_VOTERS, _rejected_voters_list.size(), + TOTAL_VOTERS, ProgressReportDataDb.totalVoters.at(prefix).getOrDefault(0), + APPROVED_VOTES, budgetApprovedVotes.at(prefix).getOrDefault(BigInteger.ZERO), + REJECTED_VOTES, budgetRejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO), + TOTAL_VOTES, ProgressReportDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)); } @Override @@ -2208,7 +2178,7 @@ public void set_swap_count(int value) { @External(readonly = true) public int getSwapCount() { - return swapCount.get(); + return swapCount.getOrDefault(0); } @Override @@ -2293,28 +2263,32 @@ public List> get_active_proposals(Address _wallet_address) { } - /*** Returns a dict of proposals of provided status :param walletAddress : user Signing in :type walletAddress : "iconservice.base.address" :return: List of all proposals_details ***/ + @Override @External(readonly = true) - public Map getProposalDetailByWallet(Address walletAddress) { + public Map getProposalDetailByWallet(Address walletAddress, @Optional int startIndex) { List> _proposals_list = new ArrayList<>(); ArrayDB projects = contributorProjects.at(walletAddress); - for (int i = 0; i < projects.size(); i++) { + int endIndex = startIndex + 5; + int size = projects.size(); + if (endIndex > size) { + endIndex = size; + } + for (int i = startIndex; i < endIndex; i++) { Map _proposal_details = getProposalDetails(projects.get(i)); _proposals_list.add(_proposal_details); } - return Map.of(DATA, _proposals_list, COUNT, _proposals_list.size()); + return Map.of(DATA, _proposals_list, COUNT, size); } - @Override @External(readonly = true) - public Map get_proposal_detail_by_wallet(Address _wallet_address) { - return getProposalDetailByWallet(_wallet_address); + public Map get_proposal_detail_by_wallet(Address _wallet_address, @Optional int startIndex) { + return getProposalDetailByWallet(_wallet_address, startIndex); } @Override