From 7a898322153572ec41d699566b323089f2524664 Mon Sep 17 00:00:00 2001 From: Ryan Sauge Date: Wed, 19 Jul 2023 11:39:48 +0200 Subject: [PATCH 1/6] Add FAQ, update doc audit --- FAQ.md | 81 ++++++++++++++++++ README.md | 2 +- .../ABDK-CMTAT-audit-20210910.pdf | Bin .../CMTAT-Audit-20210910-summary.odt | Bin .../CMTAT-Audit-20210910-summary.pdf | Bin .../ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf | Bin .../Taurus. Audit 3.3. Collected.ods | Bin 0 -> 17980 bytes .../Taurus.Audit3.1.CollectedIssues.ods | Bin 0 -> 23068 bytes .../Taurus.Audit3.1.CollectedIssues.ods | Bin 23228 -> 0 bytes 9 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 FAQ.md rename doc/audits/{ => ABDK-CMTAT-audit-20210910}/ABDK-CMTAT-audit-20210910.pdf (100%) rename doc/audits/{workDocument => ABDK-CMTAT-audit-20210910}/CMTAT-Audit-20210910-summary.odt (100%) rename doc/audits/{ => ABDK-CMTAT-audit-20210910}/CMTAT-Audit-20210910-summary.pdf (100%) rename doc/audits/{ => ABDK_CMTA_CMTATRuleEngine_v_1_0}/ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf (100%) create mode 100644 doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/Taurus. Audit 3.3. Collected.ods create mode 100644 doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/Taurus.Audit3.1.CollectedIssues.ods delete mode 100644 doc/audits/workDocument/Taurus.Audit3.1.CollectedIssues.ods diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 00000000..bf292d24 --- /dev/null +++ b/FAQ.md @@ -0,0 +1,81 @@ +# FAQ + +## IDE (Truffle, Hardhat, ...) + +> Why do you continue using Truffle instead of migrating to HardHat or Foundry? + +**Hardhat VS Truffle** + +- Our tests are not working with Hardhat so to migrate to hardhat, we will have to update our tests which will require a lot of works. +- Moreover, we do not see a use case where hardhat will be better than Truffle. +- Hardhat has a lot of plugins, but for example, for the coverage, we can run the coverage without be fully compatible with Hardhat. + +**Truffle VS Foundry** + +- The plugin "upgrades plugin" by OpenZeppelin is not available with Foundry and it is a very good tool to check the proxy implementation and perform automatic tests. See [https://docs.openzeppelin.com/upgrades-plugins/1.x/](https://docs.openzeppelin.com/upgrades-plugins/1.x/) +- The tests for the gasless module (MetaTx) will be difficult to write in Solidity, see [https://github.com/CMTA/CMTAT/blob/master/test/common/MetaTxModuleCommon.js](https://github.com/CMTA/CMTAT/blob/master/test/common/MetaTxModuleCommon.js) +- OpenZeppelin, the main libraries we use, have their tests mainly written in JavaScript, so it provides good examples for our tests +- But for performance, we have seen indeed that Foundry is better than Truffle, notably to test the Snapshot Module + +> Do you plan to support Foundry in the near Future? I see a CMTAT-Foundry repo. Is it reliable? + +No, it is currently not reliable. + +We have not planned to export all the tests in their Solidity version, but some tests are available + +The repo CMTAT-Foundry will have the latest CMTAT version + +Please, note that we provide only a minimal support for the foundry repository as well as Hardhat. + +We use Truffle to maintain the project. + +> Hardhat tests: are they really working in v2.3.0? + +No, please use Truffle to run the tests + +## Modules + +> Why the Snapshot module is not audited in the version v2.3.0? + +It was out of scope because it’s not really used yet and will likely be subject to changes soon. + +At deployment, this module is not included by default + +> What is the status for ERC1404 compatibility? + +We have not planned to be fully compatible since this ERC is not an ERC, it is only an EIP. + +To be fully compatible, we have to inherit of ERC20 inside the interface and it will break our architecture. + +See [https://erc1404.org/](https://erc1404.org/) + +> What is exactly the purpose of the flag parameter in BaseModule? +> I see that it’s a variable (uint256) to include some information, but I don’t see any use case in the code. + +It is just a variable to include some additional information under the form of bit flags. +It is not used inside the code because it is destined to provide more information on the tokens to the "outside", for example for the token owners. + + + +> Question regarding the ValidationModule optional module. +> +> Why is it optional? The module is required by Pauser and Enforcer mandatory modules + +- ValidationModule is optional from the legal perspective, but you can ask admin@cmta.ch to have a better/clearer information on that. +- It is the opposite: PauseModule and EnforcementModule are required to use the ValidationModule (but indeed, you actually need the ValidationModule for the functions to be called) +- If you remove the ValidationModule and want to use the Pause and Enforcement module, you have to call the functions of modules inside the main contracts. It was initially the case but we have changed this behaviour by fixing the CVF-1 +Here an old version: [https://github.com/CMTA/CMTAT/blob/ed23bfc69cfacc932945da751485c6472705c975/contracts/CMTAT.sol#L205](https://github.com/CMTA/CMTAT/blob/ed23bfc69cfacc932945da751485c6472705c975/contracts/CMTAT.sol#L205) +The PR: [https://github.com/CMTA/CMTAT/pull/153](https://github.com/CMTA/CMTAT/pull/153) +We could probably move the ValidationModule inside the mandatory modules and think about a better architecture (but probably not for the next release) + +## Documentation + +> What is the code coverage? + +A code coverage is available here: [https://github.com/CMTA/CMTAT/blob/master/doc/general/test/coverage/index.html](https://github.com/CMTA/CMTAT/blob/master/doc/general/test/coverage/index.html) + +Normally, you can run the code coverage with `npx hardhat coverage` + +Please clone the repository and open the file inside your navigator + +You will find a summary of all automatic tests in the file [test.pdf](https://github.com/CMTA/CMTAT/blob/master/doc/general/test/test.pdf) \ No newline at end of file diff --git a/README.md b/README.md index 6b5ed5e8..d2e23bae 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ The second audit covered version [2.2](https://github.com/CMTA/CMTAT/releases/ta Version 2.3 contains the different fixes and improvements related to this audit. -The report is available in [ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf](doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf). +The report is available in [ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf](doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf). ### Tools diff --git a/doc/audits/ABDK-CMTAT-audit-20210910.pdf b/doc/audits/ABDK-CMTAT-audit-20210910/ABDK-CMTAT-audit-20210910.pdf similarity index 100% rename from doc/audits/ABDK-CMTAT-audit-20210910.pdf rename to doc/audits/ABDK-CMTAT-audit-20210910/ABDK-CMTAT-audit-20210910.pdf diff --git a/doc/audits/workDocument/CMTAT-Audit-20210910-summary.odt b/doc/audits/ABDK-CMTAT-audit-20210910/CMTAT-Audit-20210910-summary.odt similarity index 100% rename from doc/audits/workDocument/CMTAT-Audit-20210910-summary.odt rename to doc/audits/ABDK-CMTAT-audit-20210910/CMTAT-Audit-20210910-summary.odt diff --git a/doc/audits/CMTAT-Audit-20210910-summary.pdf b/doc/audits/ABDK-CMTAT-audit-20210910/CMTAT-Audit-20210910-summary.pdf similarity index 100% rename from doc/audits/CMTAT-Audit-20210910-summary.pdf rename to doc/audits/ABDK-CMTAT-audit-20210910/CMTAT-Audit-20210910-summary.pdf diff --git a/doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf b/doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf similarity index 100% rename from doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf rename to doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/ABDK_CMTA_CMTATRuleEngine_v_1_0.pdf diff --git a/doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/Taurus. Audit 3.3. Collected.ods b/doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/Taurus. Audit 3.3. Collected.ods new file mode 100644 index 0000000000000000000000000000000000000000..a544cd7e5d3efb37b83fe86b573b787b01e95014 GIT binary patch literal 17980 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 MzdM~?p+8suADWSyO#lD@ literal 0 HcmV?d00001 diff --git a/doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/Taurus.Audit3.1.CollectedIssues.ods b/doc/audits/ABDK_CMTA_CMTATRuleEngine_v_1_0/Taurus.Audit3.1.CollectedIssues.ods new file mode 100644 index 0000000000000000000000000000000000000000..683b66792039435ad7d4ce07194645103e4f8ff3 GIT binary patch literal 23068 zcmb4q18`cTSyC_tyFEUv;{6@7;Uv zUcI_|t=8(N6=lF7&_F<-|6a!X>S4A&q8LCxK>qQ6KY`d;*_pX|Ihq+cI@(&97`a+G z*fYA@n=&{UxmdX{I5?Wwn>v`d*_qk9GPpQ8n;Dt9Selu+D*iud{!Qk;9oFBFh=aYk zm4%!0f28KZ!f0;mVB~7%%=o{f`peVJ*y!I;;rt6;jt-7)j{lJUFS)roIN1JsZg~HK zn~{l$nXTF1f;#-Wd=mZ(N-H}f3o{o+VJlZVBS)8ili7b&$bT~HXk>3@`@f`faW!&v zbNSyF)6v<%!r9E_|DuG3hW-zA`dhO9cHjSo?2PQK%*|X}8Jtbcr;?}aLzs|4uX)4F zrdI_SAt9Zq#@nrP``E)ZAsO#7QMP;HlGT-pD$a5j_iMyicjB4=mqvJ_(G6w&s%$3I z5foMqE=A`3cBgpavl;C z1SA9;1mr*4z`v@#|7eY7u0{-=cDAue6ZTn5XyMO(um|RF!+jtoL8NBLZiyAC+=&gi z%ug_G=k*dTFbl1WD`RfRKOv8gdD4N773cR#kP3#`Y#ricQA!}0xWsNch3{K-ngupb z#VqmhN#N+=9ul+syul8^#A-b2+Qh1{{yqT(SkHchk5;C((aBu$PSIlffEy`cAUZv^ ziE}J>Ww}+Bt1732{56O&4EvW#DHS?wWn8=UYcXutA%O#gZsYoKU~! zju8rSSHo}y9Irg{yPln?XB^`Ln&0y8hR(6UyD#Hi7~^wyiQ1}6yw<#aj%`hMN<<8Q zS&->MI+}umGx@Wtt^lfgzZ^)$z|XNvfj++Jy-I*Q4Kf9~ze+7i7D6wCCJLn$7N$|w zm87^7KQHncnpO_Fnbs~k;24zn(-9^AB%Eg8;NmzgWoPv1-TdCh>K4H(dkp9V8ApBq z-*dw1+s=3#fio>bAlu=904r?IeQA@Dr*)9GSW)a%Uv|V~Z@6RvWSKYJKDf6&Hixt=H(p4K{XwpbniD5gV90Jg6U{F!ULua5%SOQIp2ZYGPT*GE7(Nxu$uM+1k2*x<0^@{pXy zOs0ad#gKoRgWfr@?N7&qbIr@VUb-^fEkHTP{Ro)M> zi>D748E-4W7;n9lojqzor?9E6C7Nz|VwSMOg3~OQzS0+o>1C%nAYf&qi1+p z3h@jkz6#zP$&sKJ!`m}A>>V#cMcDfg;&rrxM(|QT(zM79zXaESa}wk-3w&T1i;JS) znKo+0i8v{;Rm`^13ni~687kN$B&fT=$;t_^NcAxn?$RxAJE+X{bnBTp{CdLMY9*ve z;@aTWe1FbpZh>0uVOtlRk}Le=i~#||b}miS&7dmPZ48j3mnzcnYzhgXQf0++-i5eT zn_}v1;1??XIA0iXtz+$_F9_zqe8Cg{y==r zbDoVj6RZ7gN$?mVRneRRc4nI)?m|4oaHuQBJ_4i?{XST>vHgK2oVUwQa7PZucT151 zDhXtit3VGvB1QGKTZ}pWKLWD>D^td1mg|uZXigUb5+(6ungTc|-{rwdF_FR9qsH)_OfGufMHA8{kI7$chh~w`Cx)WFEk>4K=k_C^*Wh{@A$aj%tK^qET zb6^k=?#L%>#TF-H_ca|12}tNjEehA)*+` z4J-$RaB)}}DrbCRw2FTbwn#y$bqAu2qc82CPi3zOW=1?v)65qU}tVx-*RSpW_EAa ztjg;he7VPYz2`XW6g#M!T&2?DdBd7-mb*LU#hRi6mUg+;Oj|+> zNfHN`WvpNiEl{tS{D$hJl9cREb>>rCgZCN1=J(ko*npFd&Nuh`?Bel?_VA{uDuUbbYzAzc%yUOHL&+^$Y1V%Ma$?IENa8w_{mwF z!(e#M{QlBiSSFpZDPH>QnLlz$f2KS}TQ>XH(9lc|@nba7>$qy1Ke{#QO}_8g^KR{e zC-N7wx`z?*v3Qwbv*TYm>G4_Tzxp6=cKLa|?>GE>yS?|`#@{n?IsWv5MCc3g4I^gQ(EME2Hs-lIxq!vWN_q%Cm5jZHRdpv7st%gdHws~oI zv}FoaXtghTfXjpxBb-BxDjN!560jM8r`mDrv)i~5^B4o1>;7WW70k;N17I~$K=sb2gP>*DL%H(GbP@MS1X9z9o@roGqmC#sdMYaKYT#Nb%ahQt7Uv$yE;l%^EUj;Mi!=2f|v3%V)LzqljkIK|e^2F4oM#ULkiB(DM+8JK6)02$D z;cKyJ{X>?S_D!b0MI$#~o^&nE72Z0u#J((|b0G@8L*9bcBn_l2`e75e)#P3F_eNZP z;2Nh>GZc&J_H3!rV+AG1VM{s4V{m@5hOb?c9l~{D-Ui! zjX+-I|0aPD+#aUFthEtf7d5$t5ES2*@PlQsdNfh!8rX+`<~tCRdAFtEn&b2beb~9u zokatkKMDn746POxvb3Z%dTmZA5q$8^WUUx12i(%NWtfvJU%>O#RdOPqUFVyy9@J6|- z5*_Rk)?L?dDj)_p1oPZbbbG&nLex&+A~qiYryO}-ibL&0>dukd9oB3nj0OdjA%D?7 z+eBFcAGF#+|2oo=iWcnn#VG=J;b1|pfK0pmJ75k34@MXxGtt-zchROO$snjtJ zfB%*}&DlIuWeffaAN}f@X@``aJ(wQGKjwWR-=;HFKt(>OqSgVd`}3v4w7rB=9f=UH zIwda)THa49I$n{JSak+0H2w@EIta;>f7 zQXq}wFVIVJcwSx=sfAiKNZ)l-g4`9JUJWXqoop1&${P80J`aE`hFgM&IpH?J4L)7nFP??O-|wo8O&!OSpaP2?eO-F`;~vV$x)&n^fkz2_l1aN zxlo1T{hm2+{XKy|j!H%e5tBmwCo&!8hKLcaRMtcU zCc@~2n$Ew#Hj~jZGcEqwK0;aA07`t-W@@j$qCodx<+!$RzflBzql!h{_Wm7rp{#v; z8DZm4qlVK)i*PzIP~Q~LICUtwDkoo|n?s7#qfOuHu>I^39!ZKTk}Wh_>TmC(Lg(j& zikw(Uwem_RH=`9!(ACKr)I5oR%ELQ#H+E=&V<6Nr z*f90Ea$M*p$iCk)1725PYhJF(L%+`WY!nKp##SEjBYZ;Z4 zA5WlNp&jd@acI3?UnNlksbh@K0e^}~*{`N7SB)(>Z8uVkp(SfbG(qAwaR(DyLhT6| z29poaQDp}txFDxlq?REJbBJtbhFVn?0Iz~_l!SOzck!+_i3t4j{Sw?Sl2BU3Aw?Tb zQcfovanZ4%*5-O@S$Icy;><0eGF60d8pWi=zAyKc0uo>q4Ke`~Mk=WEvGWfi$H)V#~zW1QjI7I|+Xr3Q4Mbw?YJQAUul zEm;J6_Z5QrBKx-I8>x@@+5lTB$S6J^)dvV%dx$Jt9Fl09s9UF@a_%EO5HEh#U<`k1 zREmiW;ptYI?7Ph<`a^ZOHJkxb-MlR8m%p#8>E*+&AzPx4A}K3!QC|EH zT2o|0m4emB^xrHNvgG1DfFKA%yLKOsVSz!T0RQ6Lof})KkltgHwgfh)*8*y4g>Oa- z7)34+l2672#n{_Ilc@a@pb=L97Ul24)Dk~Eq23#9;JqxmXZz4g_ps-Zr|u4^v&Vc z0xf*l@NflBK}FD}4UaY~O=))hGF8QvlRMT(NN3FLB`rVRwY$0!c)m6JsKvbCn{A%(-oBA(1Z9JNU(9;CvN1GWq0I@n8dQpK-gH#EZ#uzh zbLPjg67tZ@<{8xGkFQg{=XNP2zid{+t^#`=trdV4CrPCYa)R4Z#vkwp6D^$ zZ5u0u-=?ew6xqvnZbn}eA~i^yB}&Q->{n?zAx;_vV0dzXLIb7j zTHvkDMw3H7mCaNqiQd=kmwWgz7#UNw{T|fBs>aG%)9Z?FWc9(-RHax( z3%RnqRdnn}(}S+1APi@0 z*4QAbbDaR;ghj4LoUq0I!}KtL2||7%?NFZ=g=hx+jVG6={&{vTVls->HqvAvO%tqY^;e+3yF z?Ja&P%1gk*;{0RPftQjLRsQ=d`0Ihte~myOV!WS!?_i&bvZ`WWVBp`s!y}?#Ai;e@ zLq$fxz{bHs$H5~&BcLKAB*q}3As`_qB&R3AMkK*TA}1kapundfBO#%nqai1ur=cdH zW@2PvW2K|uU}0oqW9R(A!^6(R&CAEYDadhOBdR1Xt0^y`_BSIcD$43wYFfHl>MFXLsyaH_a+=1qjt*fo0i>-^VtF5WGvyGFpi;J75 zhnJVPhf9FBn~#qV7B-Ls4@gA~WMly{(E(Xmf$Tg$ZdM>K50Fm;D9i)2^9XkL4e<&H z7ZnAH$N;59fYP!+8D*fd98g6WsHy|hRsrg219eP*raC}N3!sfF(A5U$;R$pL{OJ`O z?H&a54hH)F1O~d>gnHSB__%}x_(b}EVR%Vyh=cPp#X2cZ% zlFD+DEAvvT3o@F@bBhWKtILY2tE)?@8!H+*nyX7%8*93oDq5TBo7;POI$AqByFx>O zVF|$KBw$40POA`>>Qlx8J%nH19tuf z_KX7iTC0Dz)%@;k`rX|&+S4@92^<;d8SQJC80`A}`*;8F#NhbM^yu%2$;rXV#fh1@ zso8~z`St15orUrK`RVcH`Kh(pk@flUg@yU~<@Nd1?TzL6?X{(i&8_iq;MB_Qi8w-a!tGg?}y-ncR!RFE7{_f%V z{>kO((cbyV!TH7c{yuR3^yc8~?_c2A)$REO@ap#A^6u;Q>ip&iczXeSxV^l8xWB*u zdVKkMdAfgn1irmIeSLks4m<^efFJ}(i3+KDu3u&&rl5}ajY!EXJUl9_m&nbBe~q!a z|5fk+VMnKdRO3i1+?9jC5Q}s9(#{1dg>&&4@>H2E2p;0tdYLH~ALbG^BZs-F%_SOt zO1{!9h}L050x3WL`c_Jb00KNAtnWHM#Y8uux1Qb1i{C?}`bv2OJjbeJ+0(IG4wpY(2;)KU)N7P_e>)J-8Ocy zQQ|&nMDTn*bb-BgJmC%kH*y~%-3rs+_GY}&2#%F~cR73CWJ)bYN0Aw)`9AKS8Fin= z8Tr4yK3(1g9`ERgzQ%L94;dN%@`&(XyWc)Gry4SF!F`+ETu|70dtmh32CiOSzkZT7 zF3##k0Uw|o?0E!KsO@)pfft(tE;AQBk6}Cf_hIQ@A2;+i7I821`ole!lxYUqubs~` z53X9w0lOn{^j?0auMT{H5&jlSVb%9XgzvwwTpcY2e_ z^=htJr`001t&p#wnXlD^z@=I@5k_Dd{mQG)2xw0Od5hnId*kg|Ln~w3@M^CM&(wz2 zw|_FmUDp$)TjUO|rZ3}LDMvA5D=N+=vqOykLNomS7Fd)MvHgpVoLadfR#m)Jv!w+& z!%phJYjB?QR=Odn-VjM~>oe)Xg!BSXUl;J9b^K_%o%Ixh{oFecO1jVeyY&%vwM zLRLfF*Ft55c$+*Z!^72g^V4r79N5+{i`#y~YLNJSN9K1$TMMT#mEo9LR~vseMaGex zfX2vQUT33CiGuIDh(<}^5?<4$i~*naM!7UEKJ;^@*oqED)Jul%cA#{$Mn~9gxfB6z zkQsNxg4juNB7JH#sloqR$~mtT#DO74#xsY)E&waU%}-f_(lb(y9wgS0jT#PG7hhB^ z%Ttu{g3C5cNmj;_@U=Nvje?s(;Qm4;Dkuw5)!2N{vij*to)x%UsOCM;PEbvh3@TbI z8*eTHvj`i+1aCteAw8$qX8ujmf`V=?1IKKK%!Z~awor7sga@itv|3~NO`0< zfzz@{KBZ4LX)+KSN)0fgHL2&^F`K96WJE04oPl3qWry8^EUF&s_0i2M?9&mjbe?rW zfg#P2Bzq9e>P8X&ZAcsVLlMU65o}RB&_W!cW0#M$uFz(o7l&{tQ)|NUBKqs4B+ z<@I_6&*sW?EP_-;Uz!WWs8Sh`2H8VxQ^dD0GGB)X_J3CM{}2Et?3@$G2s>R9D&62y z*vr8!EuHa}tt)SNn&l)K`JDzjKw*-kpgRmO)j{F3c+ItGo9w=5@e3A0k)oPJ>Bc2` z>=8AYQF^~}a8zwbd1vt0z4h{3oI}|r|cuoupK`|-ZR<39i6EU_m*%cCHYM>Jc$DC#MvatNZX%YJ&BBtR;j@!d& zz(FEVH`*u8aKu3t6}j4s6*43f{CoXTNR`I2${@1qydPS>uWCqd#uGQbS(!N}CtwO9 z1Eg9XVjtRUl~NXcyMelK9;@o=r3^WzN$NAV`6V6dHfiJ$rRkZOx9dFh9a8~QX<2i@ z3e~((=cR-sk$z2=5DBLoFvVf3%#&ifWvd>AGWg)sxHj*Na@exqp2ssZWxhdK%++H0 zm;`nEwqp-mPyUP#@cHV{$$9AVdcU!WU2ilFuW} z4Yq7K-1}beI03O_aGSPiGe{$e5*@mK%p21}YhVU3XZX6$X}OwhPdXzI;PJUz-GG_w zgsc2pLJ|xt)Z&s<l&%5#J^dJ zlPHVBsHiBh$`+*wyDobSxNB!J0lLq(4+{}%pLk~m(lLNT>!-O4abFDdsA^dz=R;>H zqpnc+neEPFUxS`cBY52`68_c=Z6N<2ed2_klb$P=8q*#4l{bZP{3dpge9d7jCH)Iu z#ZEkiNfp;N%7BLf?NS@w%l7+l>^lmF}~*ke`Z!Hre>B40 zx@#rQy>_OkV$5xACceQAW+_=3tV>l5e8$*tWU1dW$oJHsvriRP)ZCAAqk{brx(-Wt zWv2|pOS`QK?gqHGcM&@3z3m{SY4@Y$h}%Qi<9^3ir^Ig&ulkgd4n)$cDTd6Va8-{P zXj+`n-<_u@VbIWrW0U=;9$oLZEuJ5=T}fx7Y&afP{V)9gAY^?Wuzr4iGWJCF`eQ%| zxEpy#R-F?kv9qma=Zz(2Z_ZOE3G>hosS*WcX+)UTgNQur7MbcC24g}NS=Hd{P}z01 zpv_$M!v!4n&k69jp3FwS1Mzv>FLgM$w^-K|mqh7FF!Lprcne@pCnjh}q$xCJ7t%#CGDL}rxa+WxmK&Z-6i?(jpV+e#-HQg?fv$_jPX z#G3+7zH=I$bu&I6z`N;aF*<4ozy8;9(Dp7_`;qwH01l2LxfaJUZ0h_D{(NWCtH4 zY$n~3AHbFg!j6*`g{KWfkrh6d5+b#RkHV4VYOt&LV5TnbC?%1I9Zn>Q0tdQTw>3Q= z*be;Uu?TLz7HQU-L*D;Mx=;;^_%CQTS3ct(*w;PXv8Fp;-XkfKOgGVCMdEA-DS zneZ1%E@h*{U%dTp-#-nqJzjDsD_DitR0|GwLrn%77Rg-M3n^?d1cl7#bVX__JH%yJ zc!Z&+Q1^(mO?luj<}Ag#x3h*1?b7+Lv_3TNBjE$Mk&CZ5O25=`uH1en=eV8$%BMZf z{5?pFF2fPF*qz*v|6@Y;ug3*B;xrTtYnT;PE>1xk-JKl3o}zcf*Ot_ck9H~5Dekvn zcyd4b#G-3h5_oGj9+#Gfl=8|Thm&v@Bf(r{T6jBi!25%f+tEhq!<-|Zi&*Aicni1E zZj}3wcpo#A;Y1NUG%CDOt$IQya5?JzZ%^+%|%iI9`A(#|=R(4_kgY44w%s0r;n zLE%X~%jy%44Wff+o|VP=2OVv{d(a0OL$L4-{S?$wol3upEzgEAZ0UH6CtQ!o@=xIP zZyQsgtKiPCtPmr1O1}}dOMAza^&7Z>F>xkab{zq#Svy>F@kXzkc};TlyA(0E|EJl4V2nPqgAR1ewJmpBaduC zzwbJ^I-YOUVugi$+n1WJXBG7!Hnq``df<54?xn!ZbG-NlHY-#21JBp!)s2R?2bge{ zr(bEk1J63z`h0EKV*ERIh%ed`XRIq?F%T*8TuIv+5_D1>F;q?whgx>G(FVCFue%cq z*siN;LkfwDt!R3K!anmQxQbg$Hp*GAvr`NWdS)ul-Y+i~U(>hh9ALTGcGS}#%rt8{ zbd4+4GQ-{zWWUtc9@V7JqW0r==ptX~rq)L_Te4@=;1J&VMj1J*W@G%4iH^=^WU&KW zrA;!^XKrYW-YF6bUam?0#Vob4?n40FDM(5V24eZISq4N(OkT7`*f9A254A%78%s`1 zRft|nUYzm2A!~nOJJrc@_5(yn;?FQ=> zRZBFc=J5}I=KEH^mhGdFO+;~CZ$$W!trl3lg3%f7N7!?w(6Uj((JgF4l$iBR?MK8Z zhn;2|Rkt*Ulqw&YRP_U>;ycH4AQ^CZg87sK08_Pwe#x6fX@7A5!NOmtu3Awm-hC%hM$ z8PE6UzVaT8gep4@WN;8AwOhiZ6HmfhJDL(*SzMpHukr9QtB%fBdtV7a87#A;1EZG# zTJ&uR%9rMv5<>)453eZQM26PNb1MBDOzG9G7Ly;(1sF2kL1u|_7q}IIv{8vLSZAQj zv9}Yy^9A;gu`OeJTao!MK8g{Q+MpDRVRsDhvPRE zF{LzU{ZeVGj-Tfn-`Cg9vxrRlK+3N{|HgcKH4Ze}^FgM|FF@=J=KJCDZ~*YO*PpUG zr+gnj# zd)2k5I_p`(YO85%?B>IXZ4qCh7k=NswAe^ccfalK#6P%F8K_Hgwn>$C>+H27!c4uE z<$bHo8~p6Ur$|%WxO{4ngl}YVkzYD{N>6@1egi>NT5I|hZHpg)k41D=f)APaW8Kev zML{Rc;_%w&WQ=eL{Ngg{9M(tUgFe0;9l*j~~D|LXmS6{+iUzB!P2T z$HR7a@iT04ZeHY~pec;lq3NRAY`yiq^shj*e8}ubpC@UaN3+s}y{#&V`Sj)C3`z)+ zPCXYm=H0IOKa&i!dzHn%(zZrrH%1$X>t^f zEgO>{O42jPz}Hu*a*3w2_0chfmDV)<39}b(T@=2G5xm)-rI*+2_ZxL6H~D$aD%V}K z)PifF{IqDB#_VdNuJD4-!qXKxGggh2 z$)RC?pxohPI6n)Mo*Cv2G47++uh#=Pv&qm7#6j{sJ?dr0de1C)i-#*#X#B7G4la|dP z-}HTS;RT^s|EEN&zG;IsYfc;X1q}Si*~Un&<|K5t^|X@aiul5sOmwF+^~(Gf0tsDu zp1mgR>MyRnGcDwm&5CmRN2fvd1|4Mj<^sOBHuLb>=6TP9U`w+$BJDF$gUSl?*7U{9 z%Ms;LGfwwr=|d#|4Eb3WyU>_r6x$b>bh>PC1i0-J6oag{oL#fmeYDjR76a-Cd&DS> zMD%mQ&`qJF0r8==jva$syG*wPGXJrwR@9Amb+wuJOIET4%%J*Wi>$5Oq_*71WsTvn^&= zPOZPNK0zoLU*hWqr5MX7Pv5!p12KuNnYZ$na?f~U<9dy`$4O-+FE6duZ*;fRQVSim z#!Pw!>71kf0b*l@5;LerC#^KDL&6#2%Z}|%enP_wYZbnj2l*)2@5w(faNe6<*}+A2 zn%)nInLVp9=sUMY60&(m2t`^l`PR5|JW^-t%^;}}3W#1Y48}omncqbC8n4|zJjgH`*z zh#TK-?r^~vonSW>f%y1iF63ku+Nc*V)06q+4r#8(DxH2aNC1APd z2`Ho6OQm#pZkVO1Rm|2(6 zQ&pLRJi&HkdaHFlw=t%Q5ReB!z2}1PM+D(dKQFR%z1&CL#-IW;d{lJ*#dvOMu42`P z@nJ0w(JX#=>L`;QIQ?*XP?~t>1I&_<0`w0oO8D%LR{++9-F#2+=6?YqZ|r2R#V( zx1pHswFF@V{bv*RqDK^k149$%pDNH4QJ<8I?+WW~{0fOJf&`WNe;_ZY(){exK6%+w zM{3^J##%J79s+rf%l9xIf3!9Z@>yMVOc*E1(U(N^X3+IOdi$z)HU<^nCCKw`6#KIA z=UQ~Fmq?Gp!*TrWiXun$eCG5rb?f^x(p}sWH7KI#uyTkl--#q|N2n!Fd_C2LL{OxR z&ib+_Xk@viNo;;zl5kgeo_tTp5@&tq97_A?1H($GkZTIJ{5$0SI!NVCD535_>NO=< zR#v`um~7)iLVmwJ+VU1Jz!9FFUtXnpA?%#$80v1QN`9dL{jJFA_CUWFr$x-<^Cm9c zSwX(uilMfk!Lmc3Nu5B`&BbF?!VZC&Gb_bsWv`pjsL|KZ#}9<2Y7Z~NW1cKq+C{$Z zf!0+$`^0N{R@y22i_F5(>=v6lTQ@7;Im~|MQFNcu^(S-AOQSQD_&0E;Ey7-z1yVYXwP1cO)=N~JQOdh z(&Owb^db_AhCMK+%OO`#ZG* zMon}q!CnV(kjF$!pwVk#KhL&pJvm4hhr|=O4Ny8u!$>2k$(wi&%6+?`3aNTuH*is% zBgjOWMiZuE^r+kA(1 zR*BwP(!W^S0SYnPr2L;JNKCN!;+*USK6K7WA_cR_OibVuIlR>(l+?&5zNO4C)vyxk z{ww6?iU^i$3VkZF1{RmtXH^0s*|B-@rvnQ!*-`~DZilkz3lwn$TmUeRd{RG9Y_*fsSqnqJT_*1YB_pnr+w=CF1rSZMOyVwI z{S%?IxqZ7IVWuGIkM*Cwo!b*gt_{tfGmc<*5gmWOhdV)f-_E-iREpTKvC~L2J={yp z?i_touiskAl^ri1Ip-hP;r%=QWQvXKJ*kR)bjf&ts4ox%?#`XtAVlMi00wGHeJrly z`SE(+9sv@YJALIG8*AGfk<%@2p%3(3Lly(>p`Cp#v36>o=Nr3qUN@(DK>Sx5;04cH z<3gKqJbvdz^VsWF1fxSGRO$QM7>Y&U5R5ES(xv~B2BseI zqK)xm+m=i%?JA5S)%Q)dlEOXT0{LKACD3F;zC`s10p{>EM_%J{4DK(mGuS|k-!SS$ zA)s;Y;6B}Wr4SG6?tR-~4Z*mBSQkd_?)E~i8Sjvk&kgY#IdsnLDa6VGQWYOQmX2jp z)LeFt)#SvQC(BSohB31WdNQ^1p0P+!AVk#KKFp{&pX{$-PYx)r7)q3iHtw8J{ zi!Tb*cHsd}OKUJYF~=Pxf|v{B?5251Q2EY}oDyjN@ZVMzIsA$VV0eG3d1t-*BhV?R z$kSMaWwA*_X4ihSd-{Ot+@(2(rGj=0j3;c~YV0Ds)By@Y_Od5!_p#|85BScUG{${w zt3Wn*KgnMjSA<$N7YpHaRYQCwkrTt+zo8Wof~ubYuKLblGeE9oKiXH_xwO~S&wUe2 zv3vDU$rx}0AjV{^N~?7V%y z&@_#SrR~X-r*0=CREoNeL|D{yFz0U4t_WIM{-%_jhbz4DP2R7?4UV+Jm093^QVl7G zyr~1n5s6&hQuLif5G|0bPa6;=hxQxM7DoomHC5w*41tyi4J3t!MCd?jSSKMHtq=0_ zDo)t;djlC{0WFT1X}?E%Nq(?gn80Cg12ADGh+RMDATkD2LKLq;$VccgFlrbU7la6M zbimU99chEQBMd7#g%8SgB;GK$G zXrDDG2pmX8-!y26W*rh4@MrE;3yEto+OO;;^@}uD$8Wz56K32gB2iaSw}-o<%VVp?D(@oFbB)s2ziDpYlT>kn zpHt*9q`zFJcue*2sW8b4vD2;I!&0d`?x=%roH2rLxHI+;qKl8SzVwW|;b( zKt0Vg5+06XMwG$|APTta*3z)3P4lM}Y*7!S7s7g`yM{2@VvC6IrqYzxgP1i;>QbDn zf;%7Y@JHUobiLA`_aqa%j<~Bkx?i9z0--bPrD%Gf_ncgu!4L5>n0%&Pzj*OaY$6Sz zj&m3+avrk-Fc1pCAEsChw9s{gwRnNF`LjkjI3_sZT#3J05NzA?Lm*O~k-HHIe+=W% zVnIX7H4x%_??D4rcOxw}mkMo7fVX4r_5LzA-`UxE#ND66ykB^pY4w(jMPvAUg z`IBA0gTK)%I8~M6410qXE&mF6QkG@sKw{x5I$w1f+TDCi?Rxn(>iLZf%RVTDUE@y( zDFOnYqNEiSOv^qM_+ask;P2|Tlj{g^bg9LjqNds&B)i4?2o4;^5RPF3d+P44(~A~< zzgJ(U&##lS%Tu$?Jw1Jm%z$iMjE+~?8>xNc_(f&O_c+_J9KG^IM(tDQ`CdzSFGKpJ zGk|n=eL0)DV^R%B{G!YUR2w(YcId7>1M1;jE|6{K1Tq{;1@Eq>G!it*4}vojjr4F$2bVx$dlHm*M8{V2gn9*IFfL=WC$3bOk5f{ZH)U)UCA>K8QQ#j+Dti0U3J zo+d@6Pm_g!sjix!v7PcNTy9=ryaVAOQ@gxN38;+;qm9?H+78|`o1TO?jn+!e%Ce1~ zO}neDCF^vJvyJopkbP@24^zA~36Jcj+2(kh02~KY#hp1VPiTIa6S<{iXXg>P&y0)2 zzh`)4mXbu20wU3nyBA$Y#(_1q%`J=OEe-AF70fmmk%wAH6V&9~9K0R&4ec&a=jIM{ z$Q>bl$(%2?sCT#vdm~M?4)9C__abYD5xPV`>`cFL5Azqx{W&tm=+g>tum&t8aj;H7 z_FHY<{Bd&Grx)r~k)8ypK3oL*K2C@U+Hj-9Ig_svdW--u|83=M;T7tZ8+^Ro57{-P z!C_dPvl8bfk7XsB)OGYjL4<{uzwiNus}3lP({UX)2FDrx5w_ip_0Sb+{oJ5>=2Kc| z=z3FuZ!VDnNrjF4cpapj&ytgm!ZB^)X2_&9N@IkiHG!t*5M%Ql1)~w{W}QX+WUu=G z)bEr&J8K#ULSo*>C()J}i=vp)0aeeLq$cC|lk!Xq?Cda@OSkiKZl5$F(^lHPrs zd!!>>#Oic=u=nl!#sF9hEO9E**glR0jpx%{CB>1Z8fE!G2R|dBQN-*Gfv}ZIZ#?lS!|h9o`H~ z>#2fEPt~ei$w+ccJ3-OIyg$2(D=?WhUrh{Ig8Xr)&L3Z1uaxj0xAQ~QPw(0>n*GJ* zlrr#?K)o@=!9I|##yCEu!%N^RW8$?SUR)-7#lL|;M#J4K9*$IQ3@n_z->vLVOD+B2 zYJ2(f^|(84>G$egzO~ibW6-hWKE+XU_UYw$b}D(6h(+V_P*nWzD*>*XT8_5-4E#h& z;^|l2y%dungwLSuQu(~m0=nP=80)8ChLyAp>^`xIYdtF~OUgWse@s}%_>UpJkDIy# z2GuG(Gt&-3RV>$W4Nk;rI_eR=5+2bDj6NhoF=kS8TRIC~afo6v)LM%u5x`Aa1`P8z z^y+OYk9bClmZGI~PZY*At)>f@|xjtgF z?(+|6mzl`F=U)9*fu752Je~aSFa8e620pK1bYrm0i}?2dUgqQ0CA!<(&=&bPeqG*8 z<;uYT5_-8wT=V-DnGeeRVvpPze%@8(LS<{!0{ZOW>**hI?2F1Ga@J=Lm&f-JfO%g)hdA8-Gc+x>z4)v{EadMU8rLa(W?OmCH`%d75A&$4Xs za%2Fu5@2s_b4r=i$v!fT+rp<)0&~SD-G}gq0|4pJnH1NmH+GVz+YcEW!j&+E;Sp)k zBZAi#ihxy{0^*^xDt9MUr5U;@?tlh}5@Ldb*T$|j*k&<~4-55$&cofSJ(Tmiu6CHH zh?&)F&~&KZ(euZ?@r2z`E)PJ2@tiZ(Bm*LYZO#c^Pet%W_Qw(R4!*P^=k9*E5GoCT z)sFXUld0mmd<$_!?weg{M-x5VV?c3~|Lno_98Vh}4AiKF<4H?zG%2TVGJ(;>Igs@I z5_YE>IwXyrkWkrB&1}EXUs;rv`)S&b+!-t3Fk~*k;uWpD^W%n-rqye(D5_DSylxV( z9u}f)Q(OX3c|Dvz&52jor<#w{lPWdjkD4~Wh&eZgzLTO$taE1!EeHS zOj>m2PUsH;a8$=KrLP#Ixznooc91@bir;sTXQg9R=L=1#NSz?y55d8}2r%A%c@h3u znLhN_s)imw&fZs>4Qbx3iWeRj^LuT+qs8Iwz2)D)J2+bnzeEDSIj>Bk%FYMo>d ztAxIOO5Pi>aBO~-^!>%C;dA+0VLFjb zDLW|SH{FT^;m{;asyIP7@{Dug-UTu?!IyrQ_Ijx0X-A3w)5v)SHPy9im=?OcRFPgJ zbd*R(nvqT@(mNtZNu*1WUV;P^1Qd`iB_Lqvp-Jzk6hT2yiqd;PN+`k!=Nk{|_d0X# z{8@V@&%M`P$?P9%-Ook-R2kBg#bG$uMaimm*gZnr+;P#vc&>hF(a_S5Ypf5DWdV?M z&L_MdYso2VQ!bCvBF8m7z-INVEbFAGTJElon`%qFTww;FO@&%(r`TPY6B(@ z>R#7+d+hCX9Gpyz@Ak~T`l{KWPPxJydB;?!&XboC&{3NJL($VrP!AHL<5S^dn2H z%}Dj<7@zx6hgD^AD0U)_q?6=L$tb2Upai3A{s zYA7=FYQukD40I7ZUfhk}9ki9oEwdhUk})hnLcu3ibGc3%!b+;LM1`fdo`<6em{v>s|izn<(1PZWlVXEVN!!w2xF#%Z^9|=&|ks|k*3&^VehaE1uj1y z^}R!2=n|gWD4oXD)_twf0C(DWM~rncD-e~}M|2g`a^k%XPxhqQq1el~w!Z*c#9%1a+P+2(Qi z&COzsaz|tHMsZ9kN^laEA(BFZ$*Va%I8scjDRR0H7cO{Q+Z|$&t{JOXvgPP~@+ymB z*Aw%BS40+AVv1-7c@1JSh@+{?t*ZTR`lZZ`am_HPRq=e{gC->!M}P2(Sprgv7S?de z6!D_-ixSeP>JuPxbATq>ApUwQ+Kk49Lru z;2y_q+B{v3^Zh}S4tSQNk4_Zr#GPt&yqa7TVyf>`fgzzHIZFb}9kBtyPf_}427%f~ z-E5-$-=c^D7XzH{fD~_!+4IObOgsnO3iRkxExO3|%%BXGddRgDp95Oue8l0%|3Hop zWb;Ge+5(qFkJojnitc29-yrLq%?MVa&xg|1ycEx~t{6u)sJ01?k{7hh_C7S}$wtWw zxx3Nk895zW*ex+lPi;UDcq`-gzKIU*Pcw`^o`0&X2>fIkQ7Gg2nD0_F{o7KqOm4al z>9;{7x1e@%9q1cLk)qr9h{oWJ7z)JkW9kP0Dz;!f(hPvB24e--DleV^7HKh>)WlzE z^38hw0*GN?d`{dK%LYSOk+P$E^B&G9zF8g&9PDjh_F&Zg5Vs}21fme+#Ioidmv&a@ zj(J5Ii`(af+cM?PCrOcgNHZY3$n-LUt1{Z%WJowQBtJz7s|z1Wd>N#X;|k;Qgw6j` zUj)UU4CYxP{sKWyEQCNYMWyZ87f(lCdg&EP&e&BAoK}lt3DtF7I(lk|f?6-3FyAHw zO}T|yLq3{opmZ#2$(pdv)K03+HhfA73hY2^tPyQjP~53Zg?p@lUV1KP_xc)%O{r8; z-y#me0woK!GwPB_o5Zk`32y@{YK%2v{YdE1+G28137d`GpT_cKS#}edw}Kg2Ht6MU zq2Kct(fs3w8H5N2H>K*;ndx7q+PX-u!~d2f55)91zggnJbeh+pWLLF>BZrNfpoZ>K zW~ei65)#ke%}Y3BZ9CAi^VYQUdBdRkg^uJU>zZW2c@dM^f|)zH6M^itAL;MX#cWqN z!ziW=ST+JjN+je5%}ZJ@T%8i*GneDf91=t2CeQ4Dtt3-H(;i>J{p6-v7?$iX17UBm zZMFr=9at`F!L9IV(@Zi;U-=WnnA{JZRTkF6;I&8Ris=W$6x`wC8F8AnuH@KFRu9r1nBnU#&(3lQChCJA&CcGk{w`0Z$i(pdY`1{r$w!+#ogkeR4vQX=qjf6h zxKdwOcAUcG^cU+5*iqFuV!ZK*`pX!lV5Ce(^aZk zj;j<2Q=8;a(2PZ5#`uIw>jag{KjaFqI%1>mWX=r@7wg6If7*oI>zb^S`=YpmHk z>5aM;`2?OwSwH`o@Sn=#ZZ)oWJa`ChPj7GCvMN%Li3)~qMElapgfT*myESsLswNP| zdSc(}D86EMmx$)n!2wG}!s;+xjqiKuxkoP-v3MDjqP2`LqL?OH>7SM;VRuRrTSY%& z#A(7+6=K4D2ur-dwF8eeqJ)3%6{RLVLtw^629}q%{_pTwF*iSht}VEao6%IjL&cFYuCRW65MzC}`+ zk>9TXUr^U`Cc4nW&>ZoUaoNZWR29+puA-|*Eml4PyN%Yi>>?0bj zAMnPL6Hnj0+8&jULOwcv!H~d_MI!m*w&sMQ6DA6*b>v8wj>=5*32Pi>dw^y++x*)j zKMs;(^F*^CYpSJ>I6?;TQDmCk!t5(L@Xl_ZnS@{j#9~deJheh8je22^a0c|%();2i z2`!iCs#5AmsE>UeD@l9xBPIVvRm}?0#GdO-WLJdlHw*1IK9*=7R>>ZUS)zjp#s~10 z@1(X(-2Su@-8Hv7qkR|N`h{VkW&?JrbYFm!cwFV-x7LQQE~@lNrNq406YrpD5lV5_ zPXEvFDA3?lZqp{Bi!@;fMUzE3N`{~&m?U)H0j4_8w0k)Na~SnY*hA`(JKF_SpAUEDzjy5(<(1SH zrmV;KKCp5=@pd&`S`cgFi+v=Ym~R|Z&nb#)*0om=vbthwT>X&4=;K{L!{{*Np7|Iv zFWOD&BE`l7@dIWtPKs=Yeyj%L6j-R;f_}TQu=g#kOBZjIf?Bf8iKY*hOGHs+rA1Gw zK%^ruk?WMhdCp;QI79+fL#JtuUcRBk_*P zR3ddh<#FM1?S|)g<}`FKW`;T+za=oK@Z8W;YZwkI#bi>@ikJ}D(WV^J6y^uQo+hA7 zdA-_Ez&+N0hwTdge&-I=n?=2l9?i?UDxj39uME1e zqE*||m$fYbzL($<%(%)wgCCi<9InEx%6g(&)i*(uB`#w~xiEAX+Sv$#TlYdC>pr^< z4BnqpUiUY>HecV?3Da%d!RVwU zL~!AiK;9x#Y!_Td^m3L9=JFfS?HC6lHC0jsqNSqU)4sjOHSQ9GF+n=-jksjEb_U&!n&&A?y&hPZ&VOnXq&1I6bOUlD;KE2WNF@z^YH8Ti0I!rZKiymIyp{o;46UhT^3*^a;q+r_xyov8B#|^oPBy$V_NFu19NuOyWg$X21|uldS{Y65Jy5V}fHy*9N=hV?l!M zUhcE$2wo%(LPuFoZj4WU<{>4--=`8D4$3|0HI&D#UZY-{s(P2|b4v5>3^-JFzwKjt z5GKu&w$he`G@XTb+qZmZUJYISwhuL->O>Mjs2LOp949(X(xSVbA{`UCSq^+AmAfY< z>}W|Hm*xuc$u~<>iCq7(Z zXm`~kHpF#WuWqj^juHDXJWeFID;#8BU_jU#dEim??1d}-2|I7;0`FF6)!hWckyL&o z3b)2VLOGx4jWF}tmwuDwB*t?Juhjp!kwc5*XNZQyn_z9R5rYQb3D_yQg`t2&fWW&p zS%h{tzN*Knr7e;!QwjWJpDOiYJY%m(=mqLg9)Ku7+0HE9sdeXFF3IgIy zdR&=;Owq@g^e0XEH3g3#kvlr1)~WUbH&x=B9*616hBSU`=h*y?heZ1dGZJddIOr_c z!a|?QEiZR14uzUgOGFjGz&qg}KR+>-h3)T}oo#bgb3wMH;hSu4eP7Ip`6>JUu$`G9 z(hg%R0;N5fp`@4>o#>9x6A@Guxc&K2M@=~TJ7KG&c7)%w5avq*0Ua|cU;B0nY42ou z=Z;P&=wqUBWaWcUCtSd5q`8e zbeoHUkp*1wj*j(#yzWwHIFrbhWf6oq<)1KW;6Ip|-po&gB#gXSwg$_d4M=5@a{Qhf zcGQ!85dV7gfwCuVAMqgCHH^fH_{MdaWW0Uv+QbLE8S{~&H48&Ib2@&(h$q8w+kQsW zbuVnYp8zGynCuhTizDdc?aX@Le?piHim9#|3!#mh3I=+BUPaIkS;`+*m?@{oL(0PX z0?cx4YWP8c=~r@t){+HYK2G^@sn$($0AIey;%Gt#Q$!A_O+9Rf#?PA0dRAv=YNRh> zu>R(~ZG*C8n{Rjne#x_Zi#<8oU9~yda7!9{N^8|QCk-6pCw2%nVdSmEKJT8=!e}b{ zD#N%$V|_lTh&g=wwhlzy9G>!9Qi*c8MBCGAtp?k|A9$A|)?$R-rc6@!!tm)^GEDL* z@@a7!d~Y~wZDIsugbNWCml5Q>3Vm(_E?|iNPU)zfS6L%APc-?8AgC-fkwMGAM2QA& zEU*x*sEfdF9`v|k{ch!;PlyxhEWg9y+3;#Xza?hFLvN~T#U_bImppIZpi6u+~~-cmE%S`2hO-XKPU+5thP>hnb2GN z?fsqurfTsomE8ma)+hCMH5%D%Z<=@SQ1`un}l ztNwI}`4^XSMC;#O&iJM0YQ+uzoXfAs*1!9lHS3=XiyQvwbB=KRyUQ8G^;}nQspUUi zen-0g-RTVKdM>Abar!UB>)*|OUnJzenEi@;{r~z*{)^AA2-v^-{Ju;K1pmEEzawG) zwcv~{65c@)V~vlepddCB5{64JjTB>C4Rd6eA-`w^Jgsy=Q`m3OM}9n n7Qenn&Jy2b_?9TJ{dRhP+4+9U62KTv(3+m?>on8G8A~w{+ literal 0 HcmV?d00001 diff --git a/doc/audits/workDocument/Taurus.Audit3.1.CollectedIssues.ods b/doc/audits/workDocument/Taurus.Audit3.1.CollectedIssues.ods deleted file mode 100644 index 2221c13c096efc0c78334aa927bd4ce47dc7d7a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23228 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 Date: Thu, 20 Jul 2023 15:40:58 +0200 Subject: [PATCH 2/6] Add mintBatch with tests --- .../modules/wrapper/mandatory/MintModule.sol | 29 ++++ test/common/MintModuleCommon.js | 158 ++++++++++++++++-- 2 files changed, 170 insertions(+), 17 deletions(-) diff --git a/contracts/modules/wrapper/mandatory/MintModule.sol b/contracts/modules/wrapper/mandatory/MintModule.sol index 4d6bbaf6..c781cd56 100644 --- a/contracts/modules/wrapper/mandatory/MintModule.sol +++ b/contracts/modules/wrapper/mandatory/MintModule.sol @@ -48,5 +48,34 @@ abstract contract MintModule is ERC20Upgradeable, AuthorizationModule { emit Mint(to, amount); } + /** + * + * @dev batch version of {mint}. + * + * See {ERC20-_mint}. + * + * Emits a {Mint} event. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mintBatch( + address[] calldata to, + uint256[] calldata amounts + ) public onlyRole(MINTER_ROLE) { + + require(to.length == amounts.length, "CMTAT: to and amounts length mismatch"); + + for (uint256 i = 0; i < to.length;) { + + _mint(to[i], amounts[i]); + emit Mint(to[i], amounts[i]); + unchecked { + ++i; + } + } + } + uint256[50] private __gap; } diff --git a/test/common/MintModuleCommon.js b/test/common/MintModuleCommon.js index 47f915b0..74e41aa3 100644 --- a/test/common/MintModuleCommon.js +++ b/test/common/MintModuleCommon.js @@ -1,4 +1,4 @@ -const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers') +const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers') const { ZERO_ADDRESS, MINTER_ROLE } = require('../utils') const { should } = require('chai').should() @@ -8,79 +8,203 @@ function MintModuleCommon (admin, address1, address2) { The admin is assigned the MINTER role when the contract is deployed */ it('testCanBeMintedByAdmin', async function () { + // Arrange + const value1 = new BN(20); + const value2 = new BN(50); // Arrange - Assert // Check first balance - (await this.cmtat.balanceOf(admin)).should.be.bignumber.equal('0'); + (await this.cmtat.balanceOf(admin)).should.be.bignumber.equal(BN(0)); // Act // Issue 20 and check balances and total supply - ({ logs: this.logs1 } = await this.cmtat.mint(address1, 20, { + ({ logs: this.logs1 } = await this.cmtat.mint(address1, value1, { from: admin })); // Assert - (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal('20'); - (await this.cmtat.totalSupply()).should.be.bignumber.equal('20'); + (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(value1); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(value1); + + // Assert event + // emits a Transfer event + expectEvent.inLogs(this.logs1, 'Transfer', { + from: ZERO_ADDRESS, + to: address1, + value: value1 + }) + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Mint', { + beneficiary: address1, + amount: value1 + }); // Act // Issue 50 and check intermediate balances and total supply - ({ logs: this.logs2 } = await this.cmtat.mint(address2, 50, { + ({ logs: this.logs2 } = await this.cmtat.mint(address2, value2, { from: admin })); // Assert - (await this.cmtat.balanceOf(address2)).should.be.bignumber.equal('50'); - (await this.cmtat.totalSupply()).should.be.bignumber.equal('70') + (await this.cmtat.balanceOf(address2)).should.be.bignumber.equal(value2); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(value1.add(value2)) // Assert event // emits a Transfer event expectEvent.inLogs(this.logs2, 'Transfer', { from: ZERO_ADDRESS, to: address2, - value: '50' + value: value2 }) // emits a Mint event expectEvent.inLogs(this.logs2, 'Mint', { beneficiary: address2, - amount: '50' + amount: value2 }) }) it('testCanBeMintedByANewMinter', async function () { // Arrange + const value1 = new BN(20); await this.cmtat.grantRole(MINTER_ROLE, address1, { from: admin }); // Arrange - Assert // Check first balance - (await this.cmtat.balanceOf(admin)).should.be.bignumber.equal('0'); + (await this.cmtat.balanceOf(admin)).should.be.bignumber.equal(BN(0)); // Act // Issue 20 - ({ logs: this.logs1 } = await this.cmtat.mint(address1, 20, { + ({ logs: this.logs1 } = await this.cmtat.mint(address1, value1, { from: address1 })); // Assert // Check balances and total supply - (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal('20'); - (await this.cmtat.totalSupply()).should.be.bignumber.equal('20') + (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(value1); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(value1) // Assert event // emits a Transfer event expectEvent.inLogs(this.logs1, 'Transfer', { from: ZERO_ADDRESS, to: address1, - value: '20' + value: value1 }) // emits a Mint event expectEvent.inLogs(this.logs1, 'Mint', { beneficiary: address1, - amount: '20' + amount: value1 }) }) // reverts when issuing by a non minter it('testCannotIssuingByNonMinter', async function () { + const value1 = new BN(20); + await expectRevert( + this.cmtat.mint(address1, value1, { from: address1 }), + 'AccessControl: account ' + + address1.toLowerCase() + + ' is missing role ' + + MINTER_ROLE + ) + }) + }) + + context('Batch Minting', function () { + /** + The admin is assigned the MINTER role when the contract is deployed + */ + it('testCanBeMintedByAdmin', async function () { + const tokenHolder = [admin, address1, address2] + const tokenSupplyByHolders = [BN(10), BN(100), BN(1000)] + + // Arrange - Assert + // Check first balance + for (let i = 0; i < tokenHolder.length; ++i) { + (await this.cmtat.balanceOf(tokenHolder[i])).should.be.bignumber.equal(BN(0)) + } + + // Act + // Issue 20 and check balances and total supply + ({ logs: this.logs1 } = await this.cmtat.mintBatch(tokenHolder, tokenSupplyByHolders, { + from: admin + })) + + // Assert + for (let i = 0; i < tokenHolder.length; ++i) { + (await this.cmtat.balanceOf(tokenHolder[i])).should.be.bignumber.equal(tokenSupplyByHolders[i]) + } + + (await this.cmtat.totalSupply()).should.be.bignumber.equal(tokenSupplyByHolders.reduce((a, b) => { return a.add(b) })) + + // Assert event + // emits a Transfer event + for (let i = 0; i < tokenHolder.length; ++i) { + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Transfer', { + from: ZERO_ADDRESS, + to: tokenHolder[i], + value: tokenSupplyByHolders[i] + }) + } + + for (let i = 0; i < tokenHolder.length; ++i) { + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Mint', { + beneficiary: tokenHolder[i], + amount: tokenSupplyByHolders[i] + }) + } + }) + + it('testCanBeMintedByANewMinter', async function () { + // Arrange + await this.cmtat.grantRole(MINTER_ROLE, address1, { from: admin }) + const tokenHolder = [admin, address1, address2] + const tokenSupplyByHolders = [BN(10), BN(100), BN(1000)] + + // Arrange - Assert + // Check first balance + for (let i = 0; i < tokenHolder.length; ++i) { + (await this.cmtat.balanceOf(tokenHolder[i])).should.be.bignumber.equal(BN(0)) + } + + // Act + // Issue 20 and check balances and total supply + ({ logs: this.logs1 } = await this.cmtat.mintBatch(tokenHolder, tokenSupplyByHolders, { + from: address1 + })) + + // Assert + for (let i = 0; i < tokenHolder.length; ++i) { + (await this.cmtat.balanceOf(tokenHolder[i])).should.be.bignumber.equal(tokenSupplyByHolders[i].toString()) + } + + (await this.cmtat.totalSupply()).should.be.bignumber.equal(tokenSupplyByHolders.reduce((a, b) => { return a.add(b) })) + + // Assert event + // emits a Transfer event + for (let i = 0; i < tokenHolder.length; ++i) { + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Transfer', { + from: ZERO_ADDRESS, + to: tokenHolder[i], + value: tokenSupplyByHolders[i] + }) + } + + for (let i = 0; i < tokenHolder.length; ++i) { + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Mint', { + beneficiary: tokenHolder[i], + amount: tokenSupplyByHolders[i] + }) + } + }) + + // reverts when issuing by a non minter + it('testCannotIssuingByNonMinter', async function () { + const tokenHolder = [admin, address1, address2] + const tokenSupplyByHolders = [BN(10), BN(100), BN(1000)] await expectRevert( - this.cmtat.mint(address1, 20, { from: address1 }), + this.cmtat.mintBatch(tokenHolder, tokenSupplyByHolders, { from: address1 }), 'AccessControl: account ' + address1.toLowerCase() + ' is missing role ' + From 0f830ba0c67fbff8e65121a8bc9f8cadde2ddb00 Mon Sep 17 00:00:00 2001 From: Ryan Sauge Date: Mon, 24 Jul 2023 16:49:31 +0200 Subject: [PATCH 3/6] Add burn batch with tests --- .../modules/wrapper/mandatory/BurnModule.sol | 32 ++++ .../modules/wrapper/mandatory/MintModule.sol | 11 +- package.json | 5 +- test/common/BurnModuleCommon.js | 165 +++++++++++++++--- test/common/MintModuleCommon.js | 103 ++++++----- .../SnapshotModuleUtils.js | 1 - .../modules/EnforcementModule.test.js | 1 - 7 files changed, 233 insertions(+), 85 deletions(-) diff --git a/contracts/modules/wrapper/mandatory/BurnModule.sol b/contracts/modules/wrapper/mandatory/BurnModule.sol index d9398030..61a0761f 100644 --- a/contracts/modules/wrapper/mandatory/BurnModule.sol +++ b/contracts/modules/wrapper/mandatory/BurnModule.sol @@ -38,6 +38,7 @@ abstract contract BurnModule is ERC20Upgradeable, AuthorizationModule { * @dev Destroys `amount` tokens from `account` * * See {ERC20-_burn} + * Emits a {Burn} event */ function forceBurn( address account, @@ -48,5 +49,36 @@ abstract contract BurnModule is ERC20Upgradeable, AuthorizationModule { emit Burn(account, amount, reason); } + /** + * + * @dev batch version of {mint}. + * + * See {ERC20-_burn}. + * + * Emits a {Burn} event by burn action. + * + * Requirements: + * + * - the caller must have the `BURNER_ROLE`. + */ + function forceBurnBatch( + address[] calldata accounts, + uint256[] calldata amounts, + string memory reason + ) public onlyRole(BURNER_ROLE) { + require( + accounts.length == amounts.length, + "CMTAT: accounts and amounts length mismatch" + ); + + for (uint256 i = 0; i < accounts.length; ) { + _burn(accounts[i], amounts[i]); + emit Burn(accounts[i], amounts[i], reason); + unchecked { + ++i; + } + } + } + uint256[50] private __gap; } diff --git a/contracts/modules/wrapper/mandatory/MintModule.sol b/contracts/modules/wrapper/mandatory/MintModule.sol index c781cd56..1a7fac9b 100644 --- a/contracts/modules/wrapper/mandatory/MintModule.sol +++ b/contracts/modules/wrapper/mandatory/MintModule.sol @@ -53,7 +53,7 @@ abstract contract MintModule is ERC20Upgradeable, AuthorizationModule { * @dev batch version of {mint}. * * See {ERC20-_mint}. - * + * * Emits a {Mint} event. * * Requirements: @@ -64,11 +64,12 @@ abstract contract MintModule is ERC20Upgradeable, AuthorizationModule { address[] calldata to, uint256[] calldata amounts ) public onlyRole(MINTER_ROLE) { - - require(to.length == amounts.length, "CMTAT: to and amounts length mismatch"); - - for (uint256 i = 0; i < to.length;) { + require( + to.length == amounts.length, + "CMTAT: to and amounts length mismatch" + ); + for (uint256 i = 0; i < to.length; ) { _mint(to[i], amounts[i]); emit Mint(to[i], amounts[i]); unchecked { diff --git a/package.json b/package.json index f671a668..4def96f4 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,11 @@ "lint:js:fix": "npx eslint test --fix", "lint:sol": "npx solium -d contracts", "lint:sol:fix": "npx solium -d contracts --fix", - "lint:all": "npx run lint && npm run lint:sol", - "lint:all:fix": "npx run lint:fix && npm run lint:sol:fix", + "lint:all": "npx run lint && npx run lint:sol", + "lint:all:fix": "npm run-script lint:js:fix && npm run-script lint:sol:fix", "lint:sol:prettier": "npx prettier --write 'contracts/**/*.sol'", "lint:js:prettier": "npx prettier test", + "lint:all:prettier": "npm run-script lint:js:prettier && npm run-script lint:sol:prettier", "console": "truffle console", "coverage": "npx hardhat coverage", "docgen": "npx hardhat docgen", diff --git a/test/common/BurnModuleCommon.js b/test/common/BurnModuleCommon.js index d3c235e8..7071b57a 100644 --- a/test/common/BurnModuleCommon.js +++ b/test/common/BurnModuleCommon.js @@ -1,19 +1,23 @@ -const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers') +const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers') const { BURNER_ROLE, ZERO_ADDRESS } = require('../utils') const { should } = require('chai').should() function BurnModuleCommon (admin, address1, address2) { context('Burn', function () { + const INITIAL_SUPPLY = new BN(50) + const REASON = 'BURN_TEST' + const VALUE1 = new BN(20) + const DIFFERENCE = INITIAL_SUPPLY.sub(VALUE1) + beforeEach(async function () { - await this.cmtat.mint(address1, 50, { from: admin }); - (await this.cmtat.totalSupply()).should.be.bignumber.equal('50') + await this.cmtat.mint(address1, INITIAL_SUPPLY, { from: admin }); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(INITIAL_SUPPLY) }) - it('testCanBeBurntByAdminWithAllowance', async function () { - const reason = 'BURN_TEST'; + it('testCanBeBurntByAdmin', async function () { // Act // Burn 20 - ({ logs: this.logs1 } = await this.cmtat.forceBurn(address1, 20, reason, { + ({ logs: this.logs1 } = await this.cmtat.forceBurn(address1, VALUE1, REASON, { from: admin })) // Assert @@ -21,21 +25,21 @@ function BurnModuleCommon (admin, address1, address2) { expectEvent.inLogs(this.logs1, 'Transfer', { from: address1, to: ZERO_ADDRESS, - value: '20' + value: VALUE1 }) // Emits a Burn event expectEvent.inLogs(this.logs1, 'Burn', { owner: address1, - amount: '20', - reason + amount: VALUE1, + reason: REASON }); // Check balances and total supply - (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal('30'); - (await this.cmtat.totalSupply()).should.be.bignumber.equal('30'); + (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(DIFFERENCE); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(DIFFERENCE); // Burn 30 // Act - ({ logs: this.logs2 } = await this.cmtat.forceBurn(address1, 30, reason, { + ({ logs: this.logs2 } = await this.cmtat.forceBurn(address1, DIFFERENCE, REASON, { from: admin })) // Assert @@ -43,40 +47,39 @@ function BurnModuleCommon (admin, address1, address2) { expectEvent.inLogs(this.logs2, 'Transfer', { from: address1, to: ZERO_ADDRESS, - value: '30' + value: DIFFERENCE }) // Emits a Burn event expectEvent.inLogs(this.logs2, 'Burn', { owner: address1, - amount: '30', - reason + amount: DIFFERENCE, + reason: REASON }); // Check balances and total supply - (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal('0'); - (await this.cmtat.totalSupply()).should.be.bignumber.equal('0') + (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(BN(0)); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(BN(0)) }) it('testCanBeBurntByBurnerRole', async function () { - const reason = 'BURN_TEST' // Arrange await this.cmtat.grantRole(BURNER_ROLE, address2, { from: admin }); // Act - ({ logs: this.logs } = await this.cmtat.forceBurn(address1, 20, reason, { from: address2 })); + ({ logs: this.logs } = await this.cmtat.forceBurn(address1, VALUE1, REASON, { from: address2 })); // Assert - (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal('30'); - (await this.cmtat.totalSupply()).should.be.bignumber.equal('30') + (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(DIFFERENCE); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(DIFFERENCE) // Emits a Transfer event expectEvent.inLogs(this.logs, 'Transfer', { from: address1, to: ZERO_ADDRESS, - value: '20' + value: VALUE1 }) // Emits a Burn event expectEvent.inLogs(this.logs, 'Burn', { owner: address1, - amount: '20', - reason + amount: VALUE1, + reason: REASON }) }) @@ -99,5 +102,119 @@ function BurnModuleCommon (admin, address1, address2) { ) }) }) + context('BurnBatch', function () { + const REASON = 'BURN_TEST' + const TOKEN_HOLDER = [admin, address1, address2] + const TOKEN_SUPPLY_BY_HOLDERS = [BN(10), BN(100), BN(1000)] + const INITIAL_SUPPLY = TOKEN_SUPPLY_BY_HOLDERS.reduce((a, b) => { return a.add(b) }) + const TOKEN_BY_HOLDERS_TO_BURN = [BN(5), BN(50), BN(500)] + const TOKEN_BALANCE_BY_HOLDERS_AFTER_BURN = [ + TOKEN_SUPPLY_BY_HOLDERS[0].sub(TOKEN_BY_HOLDERS_TO_BURN[0]), + TOKEN_SUPPLY_BY_HOLDERS[1].sub(TOKEN_BY_HOLDERS_TO_BURN[1]), + TOKEN_SUPPLY_BY_HOLDERS[2].sub(TOKEN_BY_HOLDERS_TO_BURN[2])] + const TOTAL_SUPPLY_AFTER_BURN = INITIAL_SUPPLY.sub(TOKEN_BY_HOLDERS_TO_BURN.reduce((a, b) => { return a.add(b) })) + + beforeEach(async function () { + // await this.cmtat.mint(address1, INITIAL_SUPPLY, { from: admin }); + ({ logs: this.logs1 } = await this.cmtat.mintBatch(TOKEN_HOLDER, TOKEN_SUPPLY_BY_HOLDERS, { + from: admin + })); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(INITIAL_SUPPLY) + }) + + it('testCanBeBurntBatchByAdmin', async function () { + // Act + // Burn + ({ logs: this.logs1 } = await this.cmtat.forceBurnBatch(TOKEN_HOLDER, TOKEN_BY_HOLDERS_TO_BURN, REASON, { + from: admin + })) + // Assert + // emits a Transfer event + // Assert event + // emits a Transfer event + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Transfer', { + from: TOKEN_HOLDER[i], + to: ZERO_ADDRESS, + value: TOKEN_BY_HOLDERS_TO_BURN[i] + }) + } + + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Burn', { + owner: TOKEN_HOLDER[i], + amount: TOKEN_BY_HOLDERS_TO_BURN[i], + reason: REASON + }) + } + // Check balances and total supply + // Assert + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + (await this.cmtat.balanceOf(TOKEN_HOLDER[i])).should.be.bignumber.equal(TOKEN_BALANCE_BY_HOLDERS_AFTER_BURN[i]) + } + + (await this.cmtat.totalSupply()).should.be.bignumber.equal(TOTAL_SUPPLY_AFTER_BURN) + }) + + it('testCanBeBurntByBurnerRole', async function () { + // Arrange + await this.cmtat.grantRole(BURNER_ROLE, address2, { from: admin }); + + // Act + // Burn + ({ logs: this.logs1 } = await this.cmtat.forceBurnBatch(TOKEN_HOLDER, TOKEN_BY_HOLDERS_TO_BURN, REASON, { + from: address2 + })) + // Assert + // emits a Transfer event + // Assert event + // emits a Transfer event + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Transfer', { + from: TOKEN_HOLDER[i], + to: ZERO_ADDRESS, + value: TOKEN_BY_HOLDERS_TO_BURN[i] + }) + } + + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + // emits a Mint event + expectEvent.inLogs(this.logs1, 'Burn', { + owner: TOKEN_HOLDER[i], + amount: TOKEN_BY_HOLDERS_TO_BURN[i] + }) + } + // Check balances and total supply + // Assert + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + (await this.cmtat.balanceOf(TOKEN_HOLDER[i])).should.be.bignumber.equal(TOKEN_BALANCE_BY_HOLDERS_AFTER_BURN[i]) + } + + (await this.cmtat.totalSupply()).should.be.bignumber.equal(TOTAL_SUPPLY_AFTER_BURN) + }) + + it('testCannotBeBurntIfOneBalanceExceeds', async function () { + const TOKEN_BY_HOLDERS_TO_BURN_FAIL = [BN(5), BN(50), BN(5000000)] + // Act + await expectRevert( + this.cmtat.forceBurnBatch(TOKEN_HOLDER, TOKEN_BY_HOLDERS_TO_BURN_FAIL, '', { from: admin }), + 'ERC20: burn amount exceeds balance' + ) + }) + + it('testCannotBeBurntWithoutBurnerRole', async function () { + // Act + await expectRevert( + this.cmtat.forceBurnBatch(TOKEN_HOLDER, TOKEN_BY_HOLDERS_TO_BURN, '', { from: address2 }), + 'AccessControl: account ' + + address2.toLowerCase() + + ' is missing role ' + + BURNER_ROLE + ) + }) + }) } module.exports = BurnModuleCommon diff --git a/test/common/MintModuleCommon.js b/test/common/MintModuleCommon.js index 74e41aa3..39900292 100644 --- a/test/common/MintModuleCommon.js +++ b/test/common/MintModuleCommon.js @@ -4,67 +4,67 @@ const { should } = require('chai').should() function MintModuleCommon (admin, address1, address2) { context('Minting', function () { + const VALUE1 = new BN(20) + const VALUE2 = new BN(50) /** The admin is assigned the MINTER role when the contract is deployed */ it('testCanBeMintedByAdmin', async function () { // Arrange - const value1 = new BN(20); - const value2 = new BN(50); + // Arrange - Assert // Check first balance (await this.cmtat.balanceOf(admin)).should.be.bignumber.equal(BN(0)); // Act // Issue 20 and check balances and total supply - ({ logs: this.logs1 } = await this.cmtat.mint(address1, value1, { + ({ logs: this.logs1 } = await this.cmtat.mint(address1, VALUE1, { from: admin })); // Assert - (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(value1); - (await this.cmtat.totalSupply()).should.be.bignumber.equal(value1); + (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(VALUE1); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(VALUE1) // Assert event // emits a Transfer event expectEvent.inLogs(this.logs1, 'Transfer', { from: ZERO_ADDRESS, to: address1, - value: value1 + value: VALUE1 }) // emits a Mint event expectEvent.inLogs(this.logs1, 'Mint', { beneficiary: address1, - amount: value1 + amount: VALUE1 }); // Act // Issue 50 and check intermediate balances and total supply - ({ logs: this.logs2 } = await this.cmtat.mint(address2, value2, { + ({ logs: this.logs2 } = await this.cmtat.mint(address2, VALUE2, { from: admin })); // Assert - (await this.cmtat.balanceOf(address2)).should.be.bignumber.equal(value2); - (await this.cmtat.totalSupply()).should.be.bignumber.equal(value1.add(value2)) + (await this.cmtat.balanceOf(address2)).should.be.bignumber.equal(VALUE2); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(VALUE1.add(VALUE2)) // Assert event // emits a Transfer event expectEvent.inLogs(this.logs2, 'Transfer', { from: ZERO_ADDRESS, to: address2, - value: value2 + value: VALUE2 }) // emits a Mint event expectEvent.inLogs(this.logs2, 'Mint', { beneficiary: address2, - amount: value2 + amount: VALUE2 }) }) it('testCanBeMintedByANewMinter', async function () { // Arrange - const value1 = new BN(20); await this.cmtat.grantRole(MINTER_ROLE, address1, { from: admin }); // Arrange - Assert // Check first balance @@ -72,33 +72,32 @@ function MintModuleCommon (admin, address1, address2) { // Act // Issue 20 - ({ logs: this.logs1 } = await this.cmtat.mint(address1, value1, { + ({ logs: this.logs1 } = await this.cmtat.mint(address1, VALUE1, { from: address1 })); // Assert // Check balances and total supply - (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(value1); - (await this.cmtat.totalSupply()).should.be.bignumber.equal(value1) + (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal(VALUE1); + (await this.cmtat.totalSupply()).should.be.bignumber.equal(VALUE1) // Assert event // emits a Transfer event expectEvent.inLogs(this.logs1, 'Transfer', { from: ZERO_ADDRESS, to: address1, - value: value1 + value: VALUE1 }) // emits a Mint event expectEvent.inLogs(this.logs1, 'Mint', { beneficiary: address1, - amount: value1 + amount: VALUE1 }) }) // reverts when issuing by a non minter it('testCannotIssuingByNonMinter', async function () { - const value1 = new BN(20); await expectRevert( - this.cmtat.mint(address1, value1, { from: address1 }), + this.cmtat.mint(address1, VALUE1, { from: address1 }), 'AccessControl: account ' + address1.toLowerCase() + ' is missing role ' + @@ -108,48 +107,48 @@ function MintModuleCommon (admin, address1, address2) { }) context('Batch Minting', function () { + const TOKEN_HOLDER = [admin, address1, address2] + const TOKEN_SUPPLY_BY_HOLDERS = [BN(10), BN(100), BN(1000)] + /** The admin is assigned the MINTER role when the contract is deployed */ it('testCanBeMintedByAdmin', async function () { - const tokenHolder = [admin, address1, address2] - const tokenSupplyByHolders = [BN(10), BN(100), BN(1000)] - // Arrange - Assert // Check first balance - for (let i = 0; i < tokenHolder.length; ++i) { - (await this.cmtat.balanceOf(tokenHolder[i])).should.be.bignumber.equal(BN(0)) + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + (await this.cmtat.balanceOf(TOKEN_HOLDER[i])).should.be.bignumber.equal(BN(0)) } // Act // Issue 20 and check balances and total supply - ({ logs: this.logs1 } = await this.cmtat.mintBatch(tokenHolder, tokenSupplyByHolders, { + ({ logs: this.logs1 } = await this.cmtat.mintBatch(TOKEN_HOLDER, TOKEN_SUPPLY_BY_HOLDERS, { from: admin })) // Assert - for (let i = 0; i < tokenHolder.length; ++i) { - (await this.cmtat.balanceOf(tokenHolder[i])).should.be.bignumber.equal(tokenSupplyByHolders[i]) + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + (await this.cmtat.balanceOf(TOKEN_HOLDER[i])).should.be.bignumber.equal(TOKEN_SUPPLY_BY_HOLDERS[i]) } - (await this.cmtat.totalSupply()).should.be.bignumber.equal(tokenSupplyByHolders.reduce((a, b) => { return a.add(b) })) + (await this.cmtat.totalSupply()).should.be.bignumber.equal(TOKEN_SUPPLY_BY_HOLDERS.reduce((a, b) => { return a.add(b) })) // Assert event // emits a Transfer event - for (let i = 0; i < tokenHolder.length; ++i) { + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { // emits a Mint event expectEvent.inLogs(this.logs1, 'Transfer', { from: ZERO_ADDRESS, - to: tokenHolder[i], - value: tokenSupplyByHolders[i] + to: TOKEN_HOLDER[i], + value: TOKEN_SUPPLY_BY_HOLDERS[i] }) } - for (let i = 0; i < tokenHolder.length; ++i) { + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { // emits a Mint event expectEvent.inLogs(this.logs1, 'Mint', { - beneficiary: tokenHolder[i], - amount: tokenSupplyByHolders[i] + beneficiary: TOKEN_HOLDER[i], + amount: TOKEN_SUPPLY_BY_HOLDERS[i] }) } }) @@ -157,54 +156,54 @@ function MintModuleCommon (admin, address1, address2) { it('testCanBeMintedByANewMinter', async function () { // Arrange await this.cmtat.grantRole(MINTER_ROLE, address1, { from: admin }) - const tokenHolder = [admin, address1, address2] - const tokenSupplyByHolders = [BN(10), BN(100), BN(1000)] + const TOKEN_HOLDER = [admin, address1, address2] + const TOKEN_SUPPLY_BY_HOLDERS = [BN(10), BN(100), BN(1000)] // Arrange - Assert // Check first balance - for (let i = 0; i < tokenHolder.length; ++i) { - (await this.cmtat.balanceOf(tokenHolder[i])).should.be.bignumber.equal(BN(0)) + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + (await this.cmtat.balanceOf(TOKEN_HOLDER[i])).should.be.bignumber.equal(BN(0)) } // Act // Issue 20 and check balances and total supply - ({ logs: this.logs1 } = await this.cmtat.mintBatch(tokenHolder, tokenSupplyByHolders, { + ({ logs: this.logs1 } = await this.cmtat.mintBatch(TOKEN_HOLDER, TOKEN_SUPPLY_BY_HOLDERS, { from: address1 })) // Assert - for (let i = 0; i < tokenHolder.length; ++i) { - (await this.cmtat.balanceOf(tokenHolder[i])).should.be.bignumber.equal(tokenSupplyByHolders[i].toString()) + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { + (await this.cmtat.balanceOf(TOKEN_HOLDER[i])).should.be.bignumber.equal(TOKEN_SUPPLY_BY_HOLDERS[i]) } - (await this.cmtat.totalSupply()).should.be.bignumber.equal(tokenSupplyByHolders.reduce((a, b) => { return a.add(b) })) + (await this.cmtat.totalSupply()).should.be.bignumber.equal(TOKEN_SUPPLY_BY_HOLDERS.reduce((a, b) => { return a.add(b) })) // Assert event // emits a Transfer event - for (let i = 0; i < tokenHolder.length; ++i) { + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { // emits a Mint event expectEvent.inLogs(this.logs1, 'Transfer', { from: ZERO_ADDRESS, - to: tokenHolder[i], - value: tokenSupplyByHolders[i] + to: TOKEN_HOLDER[i], + value: TOKEN_SUPPLY_BY_HOLDERS[i] }) } - for (let i = 0; i < tokenHolder.length; ++i) { + for (let i = 0; i < TOKEN_HOLDER.length; ++i) { // emits a Mint event expectEvent.inLogs(this.logs1, 'Mint', { - beneficiary: tokenHolder[i], - amount: tokenSupplyByHolders[i] + beneficiary: TOKEN_HOLDER[i], + amount: TOKEN_SUPPLY_BY_HOLDERS[i] }) } }) // reverts when issuing by a non minter it('testCannotIssuingByNonMinter', async function () { - const tokenHolder = [admin, address1, address2] - const tokenSupplyByHolders = [BN(10), BN(100), BN(1000)] + const TOKEN_HOLDER = [admin, address1, address2] + const TOKEN_SUPPLY_BY_HOLDERS = [BN(10), BN(100), BN(1000)] await expectRevert( - this.cmtat.mintBatch(tokenHolder, tokenSupplyByHolders, { from: address1 }), + this.cmtat.mintBatch(TOKEN_HOLDER, TOKEN_SUPPLY_BY_HOLDERS, { from: address1 }), 'AccessControl: account ' + address1.toLowerCase() + ' is missing role ' + diff --git a/test/common/SnapshotModuleCommon/SnapshotModuleUtils/SnapshotModuleUtils.js b/test/common/SnapshotModuleCommon/SnapshotModuleUtils/SnapshotModuleUtils.js index 844f1b4f..c2a74fd8 100644 --- a/test/common/SnapshotModuleCommon/SnapshotModuleUtils/SnapshotModuleUtils.js +++ b/test/common/SnapshotModuleCommon/SnapshotModuleUtils/SnapshotModuleUtils.js @@ -1,4 +1,3 @@ - const getUnixTimestamp = () => { return Math.round(new Date().getTime() / 1000) } diff --git a/test/standard/modules/EnforcementModule.test.js b/test/standard/modules/EnforcementModule.test.js index 305fb267..3f4f6a67 100644 --- a/test/standard/modules/EnforcementModule.test.js +++ b/test/standard/modules/EnforcementModule.test.js @@ -1,4 +1,3 @@ - const CMTAT = artifacts.require('CMTAT_STANDALONE') const EnforcementModuleCommon = require('../../common/EnforcementModuleCommon') const { ZERO_ADDRESS } = require('../../utils') From 4e27c751e883b7f0834a91ac0d346384ebf42c61 Mon Sep 17 00:00:00 2001 From: Ryan Sauge Date: Tue, 25 Jul 2023 11:42:19 +0200 Subject: [PATCH 4/6] Batch functions: update doc modules --- .../modules/wrapper/mandatory/BurnModule.sol | 4 +- .../modules/wrapper/mandatory/MintModule.sol | 12 +-- doc/modules/presentation/mandatory/burn.md | 46 ++++---- .../presentation/mandatory/enforcement.md | 2 +- doc/modules/presentation/mandatory/mint.md | 25 ++++- .../schema/sol2uml/mandatory/BurnModule.svg | 101 +++++++++--------- .../schema/sol2uml/mandatory/MintModule.svg | 101 +++++++++--------- .../surya_graph_BurnModule.sol.png | Bin 75314 -> 80510 bytes .../surya_graph_MintModule.sol.png | Bin 72991 -> 78063 bytes 9 files changed, 152 insertions(+), 139 deletions(-) diff --git a/contracts/modules/wrapper/mandatory/BurnModule.sol b/contracts/modules/wrapper/mandatory/BurnModule.sol index 61a0761f..4ae235ac 100644 --- a/contracts/modules/wrapper/mandatory/BurnModule.sol +++ b/contracts/modules/wrapper/mandatory/BurnModule.sol @@ -51,9 +51,9 @@ abstract contract BurnModule is ERC20Upgradeable, AuthorizationModule { /** * - * @dev batch version of {mint}. + * @dev batch version of {burn}. * - * See {ERC20-_burn}. + * See {ERC20-_burn} and {OpenZeppelin ERC1155_burnBatch}. * * Emits a {Burn} event by burn action. * diff --git a/contracts/modules/wrapper/mandatory/MintModule.sol b/contracts/modules/wrapper/mandatory/MintModule.sol index 1a7fac9b..b5446bec 100644 --- a/contracts/modules/wrapper/mandatory/MintModule.sol +++ b/contracts/modules/wrapper/mandatory/MintModule.sol @@ -52,7 +52,7 @@ abstract contract MintModule is ERC20Upgradeable, AuthorizationModule { * * @dev batch version of {mint}. * - * See {ERC20-_mint}. + * See {ERC20-_mint} and {OpenZeppelin ERC1155_mintBatch}. * * Emits a {Mint} event. * @@ -61,17 +61,17 @@ abstract contract MintModule is ERC20Upgradeable, AuthorizationModule { * - the caller must have the `MINTER_ROLE`. */ function mintBatch( - address[] calldata to, + address[] calldata tos, uint256[] calldata amounts ) public onlyRole(MINTER_ROLE) { require( - to.length == amounts.length, + tos.length == amounts.length, "CMTAT: to and amounts length mismatch" ); - for (uint256 i = 0; i < to.length; ) { - _mint(to[i], amounts[i]); - emit Mint(to[i], amounts[i]); + for (uint256 i = 0; i < tos.length; ) { + _mint(tos[i], amounts[i]); + emit Mint(tos[i], amounts[i]); unchecked { ++i; } diff --git a/doc/modules/presentation/mandatory/burn.md b/doc/modules/presentation/mandatory/burn.md index 62b7311e..67ff7cc5 100644 --- a/doc/modules/presentation/mandatory/burn.md +++ b/doc/modules/presentation/mandatory/burn.md @@ -26,28 +26,6 @@ This document defines Burn Module for the CMTA Token specification. -## Sūrya's Description Report - -### Files Description Table - - -| File Name | SHA-1 Hash | -| ------------------------------------------ | ---------------------------------------- | -| ./modules/wrapper/mandatory/BurnModule.sol | 3547e217049388e5b1a48524255301aac8d301de | - - -### Contracts Description Table - - -| Contract | Type | Bases | | | -| :------------: | :-------------------------: | :-----------------------------------: | :------------: | :--------------: | -| └ | **Function Name** | **Visibility** | **Mutability** | **Modifiers** | -| | | | | | -| **BurnModule** | Implementation | ERC20Upgradeable, AuthorizationModule | | | -| └ | __BurnModule_init | Internal 🔒 | 🛑 | onlyInitializing | -| └ | __BurnModule_init_unchained | Internal 🔒 | 🛑 | onlyInitializing | -| └ | forceBurn | Public ❗️ | 🛑 | onlyRole | - ### Legend @@ -64,28 +42,44 @@ This section describes the Ethereum API of Burn Module. #### `forceBurn(address,uint256,string)` -##### Signature: +##### Definition ```solidity function forceBurn(address account,uint256 amount,string memory reason) public onlyRole(BURNER_ROLE) ``` -##### Description: +##### Description Redeem the given `amount` of tokens from the given `account`. Only authorized users are allowed to call this function. +#### `forceBurnBatch(address[],uint256[],string) ` + +##### Definition + +```solidity +function forceBurnBatch(address[] calldata accounts,uint256[] calldata amounts,string memory reason) +public onlyRole(BURNER_ROLE) +``` + +##### Description + +For each account in `accounts`, redeem the corresponding amount of tokens given by `amounts`. +Only authorized users are allowed to call this function. + +The burn `reason`is the same for all `accounts` which tokens are burnt. + ### Events #### `Burn(address,uint,string)` -##### Signature: +##### Definition ```solidity event Burn(address indexed owner, uint256 amount, string reason) ``` -##### Description: +##### Description Emitted when the specified `amount` of tokens was burnt from the specified `account`. diff --git a/doc/modules/presentation/mandatory/enforcement.md b/doc/modules/presentation/mandatory/enforcement.md index e7ab2a8b..77e7c34e 100644 --- a/doc/modules/presentation/mandatory/enforcement.md +++ b/doc/modules/presentation/mandatory/enforcement.md @@ -14,7 +14,7 @@ This document defines Enforcement Module for the CMTA Token specification. #### EnforcementModule -![surya_inheritance_EnforcementModule.sol](/home/ryan/Downloads/CM/cmtat-2.3/CMTAT-doc/doc/modules/schema/surya_inheritance/surya_inheritance_EnforcementModule.sol.png) +![surya_inheritance_EnforcementModule.sol](../../schema/surya_inheritance/surya_inheritance_EnforcementModule.sol.png) #### EnforcementModuleInternal diff --git a/doc/modules/presentation/mandatory/mint.md b/doc/modules/presentation/mandatory/mint.md index 6651c6d1..7a011814 100644 --- a/doc/modules/presentation/mandatory/mint.md +++ b/doc/modules/presentation/mandatory/mint.md @@ -33,7 +33,7 @@ This document defines Mint Module for the CMTA Token specification. | File Name | SHA-1 Hash | | ------------------------------------------ | ---------------------------------------- | -| ./modules/wrapper/mandatory/MintModule.sol | c0300d093480b66e7a9c5acd1a1c46c34f6221bb | +| ./modules/wrapper/mandatory/MintModule.sol | 59896c200ba366d171fc377d8b78d757aefbc69d | ### Contracts Description Table @@ -47,6 +47,7 @@ This document defines Mint Module for the CMTA Token specification. | └ | __MintModule_init | Internal 🔒 | 🛑 | onlyInitializing | | └ | __MintModule_init_unchained | Internal 🔒 | 🛑 | onlyInitializing | | └ | mint | Public ❗️ | 🛑 | onlyRole | +| └ | mintBatch | Public ❗️ | 🛑 | onlyRole | ### Legend @@ -56,6 +57,8 @@ This document defines Mint Module for the CMTA Token specification. | 🛑 | Function can modify state | | 💵 | Function is payable | + + ## API for Ethereum This section describes the Ethereum API of Issue Module. @@ -64,23 +67,37 @@ This section describes the Ethereum API of Issue Module. #### `mint(address,uint256)` -##### Definition: +##### Definition ```solidity function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) ``` -##### Description: +##### Description Create the given `amount` of tokens and allocate them to the given address`to`. Only authorized users are allowed to call this function. +#### `mintBatch(address[],uint256[]) ` + +##### Definition + +```solidity +function mintBatch(address[] calldata to,uint256[] calldata amounts) +public onlyRole(MINTER_ROLE) +``` + +##### Description + +For each address in `to`, create the corresponding amount of tokens given by `amounts` and allocate them to the given address`to`. +Only authorized users are allowed to call this function. + ### Events #### `Mint(address,uint256)` -##### Definition: +##### Definition ```solidity diff --git a/doc/modules/schema/sol2uml/mandatory/BurnModule.svg b/doc/modules/schema/sol2uml/mandatory/BurnModule.svg index 6a6c60e2..08a35b36 100644 --- a/doc/modules/schema/sol2uml/mandatory/BurnModule.svg +++ b/doc/modules/schema/sol2uml/mandatory/BurnModule.svg @@ -4,69 +4,70 @@ - - + + UmlClassDiagram - + cluster_0 - -contracts/modules/security + +contracts/modules/security cluster_1 - + contracts/modules/wrapper/mandatory - + -19 - -<<Abstract>> -AuthorizationModule -contracts/modules/security/AuthorizationModule.sol - -Private: -   __gap: uint256[50] -Public: -   BURNER_ROLE: bytes32 -   ENFORCER_ROLE: bytes32 -   MINTER_ROLE: bytes32 -   PAUSER_ROLE: bytes32 -   SNAPSHOOTER_ROLE: bytes32 -   DEBT_ROLE: bytes32 -   DEBT_CREDIT_EVENT_ROLE: bytes32 - -Internal: -    __AuthorizationModule_init(admin: address) <<onlyInitializing>> -    __AuthorizationModule_init_unchained(admin: address) <<onlyInitializing>> -Public: -    hasRole(role: bytes32, account: address): bool +17 + +<<Abstract>> +AuthorizationModule +contracts/modules/security/AuthorizationModule.sol + +Private: +   __gap: uint256[50] +Public: +   BURNER_ROLE: bytes32 +   ENFORCER_ROLE: bytes32 +   MINTER_ROLE: bytes32 +   PAUSER_ROLE: bytes32 +   SNAPSHOOTER_ROLE: bytes32 +   DEBT_ROLE: bytes32 +   DEBT_CREDIT_EVENT_ROLE: bytes32 + +Internal: +    __AuthorizationModule_init(admin: address) <<onlyInitializing>> +    __AuthorizationModule_init_unchained(admin: address) <<onlyInitializing>> +Public: +    hasRole(role: bytes32, account: address): bool - + -24 - -<<Abstract>> -BurnModule -contracts/modules/wrapper/mandatory/BurnModule.sol - -Private: -   __gap: uint256[50] - -Internal: -    __BurnModule_init(name_: string, symbol_: string, admin: address) <<onlyInitializing>> -    __BurnModule_init_unchained() <<onlyInitializing>> -Public: -    <<event>> Burn(owner: address, amount: uint256, reason: string) -    forceBurn(account: address, amount: uint256, reason: string) <<onlyRole>> +27 + +<<Abstract>> +BurnModule +contracts/modules/wrapper/mandatory/BurnModule.sol + +Private: +   __gap: uint256[50] + +Internal: +    __BurnModule_init(name_: string, symbol_: string, admin: address) <<onlyInitializing>> +    __BurnModule_init_unchained() <<onlyInitializing>> +Public: +    <<event>> Burn(owner: address, amount: uint256, reason: string) +    forceBurn(account: address, amount: uint256, reason: string) <<onlyRole>> +    forceBurnBatch(accounts: address[], amounts: uint256[], reason: string) <<onlyRole>> - + -24->19 - - +27->17 + + diff --git a/doc/modules/schema/sol2uml/mandatory/MintModule.svg b/doc/modules/schema/sol2uml/mandatory/MintModule.svg index ab3444ef..74239d2c 100644 --- a/doc/modules/schema/sol2uml/mandatory/MintModule.svg +++ b/doc/modules/schema/sol2uml/mandatory/MintModule.svg @@ -4,69 +4,70 @@ - - + + UmlClassDiagram - + cluster_0 - -contracts/modules/security + +contracts/modules/security cluster_1 - + contracts/modules/wrapper/mandatory - + -19 - -<<Abstract>> -AuthorizationModule -contracts/modules/security/AuthorizationModule.sol - -Private: -   __gap: uint256[50] -Public: -   BURNER_ROLE: bytes32 -   ENFORCER_ROLE: bytes32 -   MINTER_ROLE: bytes32 -   PAUSER_ROLE: bytes32 -   SNAPSHOOTER_ROLE: bytes32 -   DEBT_ROLE: bytes32 -   DEBT_CREDIT_EVENT_ROLE: bytes32 - -Internal: -    __AuthorizationModule_init(admin: address) <<onlyInitializing>> -    __AuthorizationModule_init_unchained(admin: address) <<onlyInitializing>> -Public: -    hasRole(role: bytes32, account: address): bool +17 + +<<Abstract>> +AuthorizationModule +contracts/modules/security/AuthorizationModule.sol + +Private: +   __gap: uint256[50] +Public: +   BURNER_ROLE: bytes32 +   ENFORCER_ROLE: bytes32 +   MINTER_ROLE: bytes32 +   PAUSER_ROLE: bytes32 +   SNAPSHOOTER_ROLE: bytes32 +   DEBT_ROLE: bytes32 +   DEBT_CREDIT_EVENT_ROLE: bytes32 + +Internal: +    __AuthorizationModule_init(admin: address) <<onlyInitializing>> +    __AuthorizationModule_init_unchained(admin: address) <<onlyInitializing>> +Public: +    hasRole(role: bytes32, account: address): bool - + -27 - -<<Abstract>> -MintModule -contracts/modules/wrapper/mandatory/MintModule.sol - -Private: -   __gap: uint256[50] - -Internal: -    __MintModule_init(name_: string, symbol_: string, admin: address) <<onlyInitializing>> -    __MintModule_init_unchained() <<onlyInitializing>> -Public: -    <<event>> Mint(beneficiary: address, amount: uint256) -    mint(to: address, amount: uint256) <<onlyRole>> +30 + +<<Abstract>> +MintModule +contracts/modules/wrapper/mandatory/MintModule.sol + +Private: +   __gap: uint256[50] + +Internal: +    __MintModule_init(name_: string, symbol_: string, admin: address) <<onlyInitializing>> +    __MintModule_init_unchained() <<onlyInitializing>> +Public: +    <<event>> Mint(beneficiary: address, amount: uint256) +    mint(to: address, amount: uint256) <<onlyRole>> +    mintBatch(to: address[], amounts: uint256[]) <<onlyRole>> - + -27->19 - - +30->17 + + diff --git a/doc/modules/schema/surya_graph/surya_graph_BurnModule.sol.png b/doc/modules/schema/surya_graph/surya_graph_BurnModule.sol.png index 7b621eb51257ac07939bf5c94707ea86c5390740..2c44984c04d6e0f1b9ce9431aacbf3c13f211a2b 100644 GIT binary patch delta 23574 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 SV$HhyzS@`d)QfS}q5lC5za`25 delta 18337 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

O5yi;-={4>u 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 diff --git a/doc/modules/schema/surya_graph/surya_graph_MintModule.sol.png b/doc/modules/schema/surya_graph/surya_graph_MintModule.sol.png index abe2b073ad7f8af1f140d1aa8aa09f88a4ab17f5..ab81b30a76f21e27cbb3a8aa12158bff4c366a0c 100644 GIT binary patch delta 21071 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� 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 Date: Thu, 27 Jul 2023 10:34:30 +0200 Subject: [PATCH 5/6] Mint and burn batch: improve and comments --- .../modules/wrapper/mandatory/BurnModule.sol | 10 ++++-- .../modules/wrapper/mandatory/MintModule.sol | 10 ++++-- test/common/BurnModuleCommon.js | 16 ++++++++++ test/common/MintModuleCommon.js | 32 ++++++++++++++----- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/contracts/modules/wrapper/mandatory/BurnModule.sol b/contracts/modules/wrapper/mandatory/BurnModule.sol index 4ae235ac..d1d540b8 100644 --- a/contracts/modules/wrapper/mandatory/BurnModule.sol +++ b/contracts/modules/wrapper/mandatory/BurnModule.sol @@ -51,14 +51,14 @@ abstract contract BurnModule is ERC20Upgradeable, AuthorizationModule { /** * - * @dev batch version of {burn}. + * @dev batch version of {forceBurn}. * * See {ERC20-_burn} and {OpenZeppelin ERC1155_burnBatch}. * * Emits a {Burn} event by burn action. * * Requirements: - * + * - `tos` and `amounts` must have the same length * - the caller must have the `BURNER_ROLE`. */ function forceBurnBatch( @@ -66,6 +66,12 @@ abstract contract BurnModule is ERC20Upgradeable, AuthorizationModule { uint256[] calldata amounts, string memory reason ) public onlyRole(BURNER_ROLE) { + require( + accounts.length > 0, + "CMTAT: tos is empty" + ); + // We do not check that amounts is not empty since + // this require will throw an error in this case. require( accounts.length == amounts.length, "CMTAT: accounts and amounts length mismatch" diff --git a/contracts/modules/wrapper/mandatory/MintModule.sol b/contracts/modules/wrapper/mandatory/MintModule.sol index b5446bec..c50f191b 100644 --- a/contracts/modules/wrapper/mandatory/MintModule.sol +++ b/contracts/modules/wrapper/mandatory/MintModule.sol @@ -57,16 +57,22 @@ abstract contract MintModule is ERC20Upgradeable, AuthorizationModule { * Emits a {Mint} event. * * Requirements: - * + * - `tos` and `amounts` must have the same length * - the caller must have the `MINTER_ROLE`. */ function mintBatch( address[] calldata tos, uint256[] calldata amounts ) public onlyRole(MINTER_ROLE) { + require( + tos.length > 0, + "CMTAT: tos is empty" + ); + // We do not check that amounts is not empty since + // this require will throw an error in this case. require( tos.length == amounts.length, - "CMTAT: to and amounts length mismatch" + "CMTAT: tos and amounts length mismatch" ); for (uint256 i = 0; i < tos.length; ) { diff --git a/test/common/BurnModuleCommon.js b/test/common/BurnModuleCommon.js index 7071b57a..c460a8ca 100644 --- a/test/common/BurnModuleCommon.js +++ b/test/common/BurnModuleCommon.js @@ -215,6 +215,22 @@ function BurnModuleCommon (admin, address1, address2) { BURNER_ROLE ) }) + + it('testCannotBurnIfLengthMismatch', async function () { + const TOKEN_HOLDER_INVALID = [admin, address1] + await expectRevert( + this.cmtat.forceBurnBatch(TOKEN_HOLDER_INVALID, TOKEN_BY_HOLDERS_TO_BURN, REASON, { from: admin }), + 'CMTAT: accounts and amounts length mismatch' + ) + }) + + it('testCannotBurnBatchIfAccountsIsEmpty', async function () { + const TOKEN_ADDRESS_TOS_INVALID = [] + await expectRevert( + this.cmtat.transferBatch(TOKEN_ADDRESS_TOS_INVALID, TOKEN_BY_HOLDERS_TO_BURN, { from: admin }), + 'CMTAT: tos is empty' + ) + }) }) } module.exports = BurnModuleCommon diff --git a/test/common/MintModuleCommon.js b/test/common/MintModuleCommon.js index 39900292..1152beba 100644 --- a/test/common/MintModuleCommon.js +++ b/test/common/MintModuleCommon.js @@ -63,7 +63,7 @@ function MintModuleCommon (admin, address1, address2) { }) }) - it('testCanBeMintedByANewMinter', async function () { + it('testCanMintByANewMinter', async function () { // Arrange await this.cmtat.grantRole(MINTER_ROLE, address1, { from: admin }); // Arrange - Assert @@ -95,7 +95,7 @@ function MintModuleCommon (admin, address1, address2) { }) // reverts when issuing by a non minter - it('testCannotIssuingByNonMinter', async function () { + it('testCannotMintByNonMinter', async function () { await expectRevert( this.cmtat.mint(address1, VALUE1, { from: address1 }), 'AccessControl: account ' + @@ -113,7 +113,7 @@ function MintModuleCommon (admin, address1, address2) { /** The admin is assigned the MINTER role when the contract is deployed */ - it('testCanBeMintedByAdmin', async function () { + it('testCanBeMintedBatchByAdmin', async function () { // Arrange - Assert // Check first balance for (let i = 0; i < TOKEN_HOLDER.length; ++i) { @@ -153,7 +153,7 @@ function MintModuleCommon (admin, address1, address2) { } }) - it('testCanBeMintedByANewMinter', async function () { + it('testCanBeMinteBatchdByANewMinter', async function () { // Arrange await this.cmtat.grantRole(MINTER_ROLE, address1, { from: admin }) const TOKEN_HOLDER = [admin, address1, address2] @@ -181,7 +181,6 @@ function MintModuleCommon (admin, address1, address2) { // Assert event // emits a Transfer event for (let i = 0; i < TOKEN_HOLDER.length; ++i) { - // emits a Mint event expectEvent.inLogs(this.logs1, 'Transfer', { from: ZERO_ADDRESS, to: TOKEN_HOLDER[i], @@ -189,8 +188,8 @@ function MintModuleCommon (admin, address1, address2) { }) } + // emits a Mint event for (let i = 0; i < TOKEN_HOLDER.length; ++i) { - // emits a Mint event expectEvent.inLogs(this.logs1, 'Mint', { beneficiary: TOKEN_HOLDER[i], amount: TOKEN_SUPPLY_BY_HOLDERS[i] @@ -198,8 +197,7 @@ function MintModuleCommon (admin, address1, address2) { } }) - // reverts when issuing by a non minter - it('testCannotIssuingByNonMinter', async function () { + it('testCannotMintBatchByNonMinter', async function () { const TOKEN_HOLDER = [admin, address1, address2] const TOKEN_SUPPLY_BY_HOLDERS = [BN(10), BN(100), BN(1000)] await expectRevert( @@ -210,6 +208,24 @@ function MintModuleCommon (admin, address1, address2) { MINTER_ROLE ) }) + + it('testCannotMintBatchIfLengthMismatch', async function () { + const TOKEN_HOLDER_INVALID = [admin, address1] + const TOKEN_SUPPLY_BY_HOLDERS = [BN(10), BN(100), BN(1000)] + await expectRevert( + this.cmtat.mintBatch(TOKEN_HOLDER_INVALID, TOKEN_SUPPLY_BY_HOLDERS, { from: admin }), + 'CMTAT: tos and amounts length mismatch' + ) + }) + + it('testCannotMintBatchIfTOSIsEmpty', async function () { + const TOKEN_HOLDER_INVALID = [] + const TOKEN_SUPPLY_BY_HOLDERS = [] + await expectRevert( + this.cmtat.mintBatch(TOKEN_HOLDER_INVALID, TOKEN_SUPPLY_BY_HOLDERS, { from: admin }), + 'CMTAT: tos is empty' + ) + }) }) } module.exports = MintModuleCommon From d0ce1dedfddf0362a0c7295ec765f80efcaedaa3 Mon Sep 17 00:00:00 2001 From: Ryan Sauge Date: Thu, 27 Jul 2023 11:12:58 +0200 Subject: [PATCH 6/6] Add function transferBatch --- .../wrapper/mandatory/ERC20BaseModule.sol | 38 ++++++- test/common/ERC20BaseModuleCommon.js | 101 +++++++++++++++++- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/contracts/modules/wrapper/mandatory/ERC20BaseModule.sol b/contracts/modules/wrapper/mandatory/ERC20BaseModule.sol index 90e2d766..11a60c9e 100644 --- a/contracts/modules/wrapper/mandatory/ERC20BaseModule.sol +++ b/contracts/modules/wrapper/mandatory/ERC20BaseModule.sol @@ -85,6 +85,42 @@ abstract contract ERC20BaseModule is ERC20Upgradeable { return result; } + /** + * @notice batch version of transfer + * @param tos can not be empty, must have the same length as values + * @param values can not be empty + * @dev See {OpenZeppelin ERC20-transfer & ERC1155-safeBatchTransferFrom}. + * + * + * Requirements: + * - `tos` and `values` must have the same length + * - `tos`cannot contain a zero address + * - the caller must have a balance cooresponding to the total values + */ + function transferBatch( + address[] calldata tos, + uint256[] calldata values + ) public { + require( + tos.length > 0, + "CMTAT: tos is empty" + ); + // We do not check that values is not empty since + // this require will throw an error in this case. + require( + tos.length == values.length, + "CMTAT: tos and values length mismatch" + ); + bool result; + for (uint256 i = 0; i < tos.length; ) { + result = ERC20Upgradeable.transfer(tos[i], values[i]); + require(result, "CMTAT: transfer failed"); + unchecked { + ++i; + } + } + } + /** * @dev See {IERC20-approve}. * @@ -106,4 +142,4 @@ abstract contract ERC20BaseModule is ERC20Upgradeable { } uint256[50] private __gap; -} +} \ No newline at end of file diff --git a/test/common/ERC20BaseModuleCommon.js b/test/common/ERC20BaseModuleCommon.js index 879f480c..fa3d15dd 100644 --- a/test/common/ERC20BaseModuleCommon.js +++ b/test/common/ERC20BaseModuleCommon.js @@ -1,8 +1,8 @@ -const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers') +const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers') const { DEFAULT_ADMIN_ROLE } = require('../utils') const { should } = require('chai').should() -function BaseModuleCommon (owner, address1, address2, address3, proxyTest) { +function BaseModuleCommon (admin, address1, address2, address3, proxyTest) { context('Token structure', function () { it('testHasTheDefinedName', async function () { // Act + Assert @@ -177,9 +177,9 @@ function BaseModuleCommon (owner, address1, address2, address3, proxyTest) { context('Transfer', function () { beforeEach(async function () { - await this.cmtat.mint(address1, 31, { from: owner }) - await this.cmtat.mint(address2, 32, { from: owner }) - await this.cmtat.mint(address3, 33, { from: owner }) + await this.cmtat.mint(address1, 31, { from: admin }) + await this.cmtat.mint(address2, 32, { from: admin }) + await this.cmtat.mint(address3, 33, { from: admin }) }) it('testTransferFromOneAccountToAnother', async function () { @@ -273,5 +273,96 @@ function BaseModuleCommon (owner, address1, address2, address3, proxyTest) { ) }) }) + + context('transferFrom', function () { + beforeEach(async function () { + await this.cmtat.mint(address1, 31, { from: admin }) + await this.cmtat.mint(address2, 32, { from: admin }) + await this.cmtat.mint(address3, 33, { from: admin }) + }) + + it('testTransferFromOneAccountToAnother', async function () { + // Act + ({ logs: this.logs } = await this.cmtat.transfer(address2, 11, { + from: address1 + })); + // Assert + (await this.cmtat.balanceOf(address1)).should.be.bignumber.equal('20'); + (await this.cmtat.balanceOf(address2)).should.be.bignumber.equal('43'); + (await this.cmtat.balanceOf(address3)).should.be.bignumber.equal('33'); + (await this.cmtat.totalSupply()).should.be.bignumber.equal('96') + // emits a Transfer event + expectEvent.inLogs(this.logs, 'Transfer', { + from: address1, + to: address2, + value: '11' + }) + }) + + // ADDRESS1 -> ADDRESS2 + it('testCannotTransferMoreTokensThanOwn', async function () { + // Act + await expectRevert( + this.cmtat.transfer(address2, 50, { from: address1 }), + 'ERC20: transfer amount exceeds balance' + ) + }) + }) + + context('transferBatch', function () { + const TOKEN_ADDRESS_TOS = [address1, address2, address3] + const TOKEN_AMOUNTS = [BN(10), BN(100), BN(1000)] + + beforeEach(async function () { + await this.cmtat.mint(admin, TOKEN_AMOUNTS.reduce((a, b) => { return a.add(b) }), { from: admin }) + }) + + it('testTransferBatch', async function () { + // Act + ({ logs: this.logs } = await this.cmtat.transferBatch(TOKEN_ADDRESS_TOS, TOKEN_AMOUNTS, { + from: admin + })); + // Assert + for (let i = 0; i < TOKEN_ADDRESS_TOS.length; ++i) { + (await this.cmtat.balanceOf(TOKEN_ADDRESS_TOS[i])).should.be.bignumber.equal(TOKEN_AMOUNTS[i]) + } + // emits a Transfer event + for (let i = 0; i < TOKEN_ADDRESS_TOS.length; ++i) { + expectEvent.inLogs(this.logs, 'Transfer', { + from: admin, + to: TOKEN_ADDRESS_TOS[i], + value: TOKEN_AMOUNTS[i] + }) + } + }) + + // ADDRESS1 -> ADDRESS2 + it('testCannotTransferBatchMoreTokensThanOwn', async function () { + const TOKEN_AMOUNTS_INVALID = [TOKEN_AMOUNTS[0], TOKEN_AMOUNTS[1].add(BN(1)), TOKEN_AMOUNTS[2]] + // Act + await expectRevert( + this.cmtat.transferBatch(TOKEN_ADDRESS_TOS, TOKEN_AMOUNTS_INVALID, { + from: admin + }), + 'ERC20: transfer amount exceeds balance' + ) + }) + + it('testCannotTransferBatchIfLengthMismatch', async function () { + const TOKEN_ADDRESS_TOS_INVALID = [address1, address2] + await expectRevert( + this.cmtat.transferBatch(TOKEN_ADDRESS_TOS_INVALID, TOKEN_AMOUNTS, { from: admin }), + 'CMTAT: tos and values length mismatch' + ) + }) + + it('testCannotTransferBatchIfTOSIsEmpty', async function () { + const TOKEN_ADDRESS_TOS_INVALID = [] + await expectRevert( + this.cmtat.transferBatch(TOKEN_ADDRESS_TOS_INVALID, TOKEN_AMOUNTS, { from: admin }), + 'CMTAT: tos is empty' + ) + }) + }) } module.exports = BaseModuleCommon