<html><head><style>
@import url(https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap);@import url('https://fonts.googleapis.com/css2?family=Source Code Pro:wght@400;500;600;700&display=swap');ul{opacity:1;}table{border:none !important;}a,code,pre,tt{overflow-wrap:break-word;word-wrap:break-word}.chroma .lntable,.chroma .lntd{margin:0;border:0;padding:0}pre,table{width:100%}.findings-count td,.findings-count th,.rating-critical,.rating-high,.rating-informational,.rating-low,.rating-medium,.status-closed,.status-open,.status-resolved{text-align:center}.rating-critical,.rating-high,.rating-informational,.rating-low,.rating-medium,.status-closed,.status-open,.status-resolved,a,h1,h2,h3{font-weight:500}:root{--color-link:#f66263;--color-heading:#f66263;--color-codeblock:#f5f2f0;--color-codeblock-border:#f5f2f0;--color-critical:#cc7ab9;--color-high:#ff6263;--color-medium:#f68463;--color-low:#f6b263;--color-informational:#6ba2f6;--color-open:#f6d263;--color-closed:#b6b6b6;--color-resolved:#9fbf9f;--size-200:0.694rem;--size-300:0.833rem;--size-400:1rem;--size-500:1.2rem;--size-600:1.44rem;--size-700:1.728rem;--size-800:2.074rem;--size-900:2.488rem}.report-container{color:#222;font-family:Montserrat,sans-serif;line-height:1.6;margin:1rem;font-size:var(--size-400)}a{color:var(--color-link)}@media screen and (min-width:1600px){.report-main{display:grid;grid-gap:1em}.toc{grid-column:1;max-width:30em}.frontpage-logo,.frontpage-subtitle,.frontpage-title,.report{grid-column:2}}@media screen and (max-width:1599px){ .report-main{ margin: 0 auto;max-width:70em} }h1,h2,h3,h4,h5,h6{margin-bottom:0}.toc>ul>li>a,dt,h4,h5,h6,table th{font-weight:600}h1,h2{color:var(--color-heading)}h3,h4,h5,h6{color:#444 !important}h1{font-size:var(--size-800)}h2{font-size:var(--size-700)}h3{font-size:var(--size-600) !important}h4{font-size:var(--size-500)}h1 strong,h2 strong,h3 strong,h4 strong{font-weight:400;font-size:.7em;font-family:"Source Code Pro",monospace}h2 strong::after{content:"\a";white-space:pre}code,pre,tt{font-family:"Source Code Pro",monospace,sans-serif;background-color:var(--color-codeblock);white-space:pre-wrap}code,tt{padding:1px 3px;border-radius:2px}pre{box-sizing:border-box;padding:10px;overflow:auto;word-break:break-all}pre code,tt{font-size:inherit;background:0 0;border:none;padding:0}.findings code,h2 code{background-color:inherit;border-width:0}@media screen and (min-width:600px){dl{display:grid;grid-gap:0.5em}dt{grid-column:1}dd{grid-column:2}}@media screen and (max-width:599px){dl{display:block}}table{background-color:inherit;max-width:100%;min-width:100%;border:none}table thead th{border-bottom:2px solid #222}table td,table th{text-align:left;border:none}table,td,th{border-collapse:collapse}.findings-count thead tr th:first-of-type{border-style:none}.findings-count tbody td:first-child{text-align:right;width:3em;padding-right:.75em;border-right:2px solid #222;font-weight:600}.findings-count td:nth-child(2),.rating-critical{background-color:var(--color-critical)}.findings-count td:nth-child(3),.rating-high{background-color:var(--color-high)}.findings-count td:nth-child(4),.rating-medium{background-color:var(--color-medium)}.findings-count td:nth-child(5),.rating-low{background-color:var(--color-low)}.findings-count td:nth-child(6),.rating-informational{background-color:var(--color-informational)}.status-open{background-color:var(--color-open)}.status-closed{background-color:var(--color-closed)}.status-resolved{background-color:var(--color-resolved)}#document-control table,.findings td,.metadata td{font-size:.9em}.findings td:first-of-type{white-space:nowrap;word-break:keep-all;font-family:"Source Code Pro",monospace;vertical-align:top}.findings td:nth-of-type(2){vertical-align:bottom}@media screen{.audit-header,.report{max-width:65rem}h1{margin-top:3em}h2{margin-top:2em}table th{padding:6px}table td{padding:8px 6px}.findings td:nth-of-type(2){min-width:2em}}.metadata td:last-of-type{background-color:#eee}.metadata td:first-of-type,.metadata td:nth-of-type(2){width:8em}.toc ul{list-style:none;margin-left:0;padding-left:0}.toc li ul{margin-left:3em}.toc{counter-reset:tocSectionCounter}.toc>ul>li::before{content:counter(tocSectionCounter) ". ";font-weight:600;padding-right:4px}.toc>ul>li{counter-increment:tocSectionCounter}.report{counter-reset:sectionCounter}.report h1::before{content:counter(sectionCounter) ". ";font-weight:400;padding-right:6px}.report h1{counter-increment:sectionCounter}hr{display:none}@media print{.landing-header{display:none}.toc li a,h1,h2{color:#222}dd,dt{margin:.2em 0;break-inside:avoid}dl,pre{page-break-inside:auto;break-inside:auto}dd,dt,pre{padding:0}.toc li a,.toc li a::after,pre{background-color:#fff}td{min-width:2em}pre,td{word-break:break-word}h1,h2{margin-top:0}#document-control,.break-before,h1,hr{page-break-before:always}h1{font-size:18pt}h2{font-size:16pt}h3{font-size:14pt}.frontpage-subtitle,h4{font-size:12pt}.toc,p,ul,ol,dl{font-size:11pt}summary{list-style:none;font-size:1.1em;margin-bottom:1em}.toc{background:0 0;max-width:100%;counter-reset:page;line-height:1.6}.toc li a::after{content:target-counter(attr(href),page);float:right;position:absolute;right:0;padding-left:3px}.toc li ul{margin-left:1.5em}.toc li{overflow-x:hidden;max-width:98.5%;text-align:left}.toc li ul li::after{content:".............................................." ".............................................." ".............................................." "........";float:left;width:0;letter-spacing:6px}footer,header{display:none}dd,li,p,p *{text-align:justify}dl{width:100%;display:flex;flex-wrap:wrap}dt{flex:1;min-width:30%}dd{flex:1;min-width:65%}.frontpage-logo{margin-top:75mm;width:65mm;padding-bottom:1cm}.report-container{height:auto}pre{display:inline;font-size:.9em}pre:first-child,pre:last-child{padding:0;margin:0;background-color:#fff}pre *{white-space:pre-wrap;background-color:var(--color-codeblock);padding:1px;word-wrap:normal}.findings td{max-width:20em;overflow-wrap:break-word;text-wrap:balance}.frontpage-title{font-size:20pt;font-weight:700}.metadata td{padding:.3em}.codequality{font-size:.95em}td{padding:4px}}.page-header{margin-top:-1cm;opacity:.8;position:running(pageHeaderRunning)}.page-header svg{width:34mm}@media screen{.page-header,.frontpage-subtitle,.frontpage-title,.frontpage-logo{display:none}.frontpage-subtitle,.frontpage-title{text-align:center}.frontpage-logo{width:10em;padding-bottom:.5em;margin-left:auto;margin-right:auto}.frontpage-title{font-size:var(--size-900);font-weight:700}.frontpage-subtitle{font-size:var(--size-500)}}@page{size:A4;margin:2cm 1.6cm;bleed:6mm}@page{@bottom-center{content:"𝗣𝗨𝗕𝗟𝗜𝗖 \A hello@iosiro.com";white-space:pre;color:#b7b7b7;font-size:9pt;font-family:Montserrat,sans-serif}@bottom-right-corner{content:counter(page);font-size:9pt}@top-center{content:element(pageHeaderRunning)}}@page:first{text-align:center;@top-center{content:none}@bottom-right-corner{content:none}}.chroma .lnlinks,a{text-decoration:none}.chroma .lntd,.codequality td{vertical-align:top;font-size:.9em}.chroma .ge,.chroma .sd{font-style:italic}.chroma .gh,.chroma .gp,.chroma .gs,.chroma .gu,.chroma .nc,.chroma .nd,.chroma .ni,.chroma .nl,.chroma .nn,.chroma .nt,.chroma .se,summary{font-weight:700}.bg,.chroma{background-color:var(--color-codeblock)}.chroma .lnlinks{outline:0;color:inherit}.chroma .lntable{border-spacing:0}.chroma .hl{background-color:#d8d8d8}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f}.chroma .line{display:flex}.chroma .k,.chroma .kc,.chroma .kd,.chroma .kn,.chroma .kr,.chroma .ow{color:#007020;font-weight:700}.chroma .cp,.chroma .cpf,.chroma .kp,.chroma .nb,.chroma .ne{color:#007020}.chroma .kt{color:#902000}.chroma .dl,.chroma .na,.chroma .s,.chroma .s1,.chroma .s2,.chroma .sa,.chroma .sb,.chroma .sc,.chroma .sd,.chroma .se,.chroma .sh{color:#4070a0}.chroma .nc,.chroma .nn{color:#0e84b5}.chroma .no{color:#60add5}.chroma .nd{color:#555}.chroma .ni{color:#d55537}.chroma .nf{color:#06287e}.chroma .nl{color:#002070}.chroma .nt{color:#062873}.chroma .nv{color:#bb60d5}.chroma .si{color:#70a0d0}.chroma .gp,.chroma .sx{color:#c65d09}.chroma .sr{color:#235388}.chroma .ss{color:#517918}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#40a070}.chroma .o{color:#666}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm{color:#60a0b0;font-style:italic}.chroma .cs{color:#60a0b0;background-color:#fff0f0}.chroma .gd{color:#a00000}.chroma .gr{color:red}.chroma .gh{color:navy}.chroma .gi{color:#00a000}.chroma .go{color:#888}.chroma .gu{color:purple}.chroma .gt{color:#04d}.chroma .gl{text-decoration:underline}.chroma .w{color:#bbb}.container{max-width:100%}
</style>
</head><body><div class="report-container">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" style="display:none;">
<defs>
<symbol id="iosiro-logo" viewBox="0 0 1233 312" preserveAspectRatio="xMidYMid meet">
<g fill="#061f45">
<path d="M171.5 300.6 c-3.9 -1.7 -9.5 -4.6 -12.5 -6.5 -5.1 -3.2 -21 -15 -21 -15.6 0 -0.2 6.1 -3.5 13.5 -7.4 7.4 -3.8 17.2 -9.6 21.8 -12.7 11.1 -7.7 24.4 -21.3 29 -29.5 8.2 -14.7 9.4 -21.4 11.2 -62 1.5 -36.7 3 -46.9 8.5 -62.1 10.1 -27.6 28.2 -43.3 68 -58.8 20.3 -8 31.8 -14.8 42.4 -25.2 l8.9 -8.8 -0.7 5.7 c-1.1 9.2 -4.7 15.7 -13.4 24.2 -9.3 9.1 -20.2 16 -49.9 31.5 -22.9 12 -27 14.8 -33.3 22.7 -8.4 10.6 -10.6 21.1 -12.5 59.2 -1.6 32.3 -2.4 39.8 -5.6 52.7 -7.4 29.9 -24.7 52.9 -51.2 68.2 l-7.7 4.4 6.4 3.6 6.4 3.5 7.9 -4.1 c4.3 -2.2 11.7 -6.7 16.5 -9.9 9.8 -6.6 30.5 -26 40.1 -37.5 8.9 -10.6 21.7 -30.5 28 -43.3 l5.2 -10.7 9.5 -4.5 c5.2 -2.5 9.6 -4.4 9.9 -4.2 1.6 1.7 -13.3 32.8 -22.4 46.7 -22.3 34 -54.5 62.6 -91.3 81.2 l-4.7 2.4 -7 -3.2z"></path>
<path d="M582.1 272 c-19.3 -4.1 -31.7 -11.4 -45.4 -26.8 -14.2 -16 -19.7 -31.4 -19.7 -55.5 0.1 -22.2 4.9 -36.2 17.4 -50.9 9.3 -10.9 16.1 -16.5 25.8 -21.4 14.5 -7.3 21.7 -8.9 39.8 -8.9 18.3 0 23.5 1.2 38.5 8.5 20.6 10 36.7 29.7 43.1 53 2.6 9.2 2.5 31.8 0 41.4 -7.3 27.2 -27.1 48.7 -53 57.3 -10.6 3.4 -11.8 3.6 -26.6 3.9 -8.5 0.2 -17.5 -0.1 -19.9 -0.6z m31 -31.4 c13.1 -2.8 21.4 -9.3 27.7 -21.3 5.1 -10 6.6 -16.5 6.5 -28.8 0 -22.7 -9.7 -39.6 -26.9 -46.9 -5.9 -2.5 -8.5 -3 -17.7 -3.4 -6.4 -0.3 -12.7 0.1 -15.5 0.8 -25.7 6.4 -40 33.3 -33.7 63.5 2.9 13.8 10.9 25.6 21.7 31.9 8.6 5 25.2 6.9 37.9 4.2z"></path>
<path d="M754 271.9 c-11.5 -3.2 -17.4 -6.4 -24.9 -13.9 -6.6 -6.6 -12.6 -14.9 -14.6 -20.1 -0.5 -1.4 2.3 -3.1 14.1 -8.8 8.1 -3.9 14.9 -7 15 -6.8 0.2 0.2 2.1 3 4.3 6.4 4.7 7.3 9 10.7 15.4 12.4 5.8 1.4 14.3 0.7 18.7 -1.6 6.2 -3.2 8.8 -14 5.1 -21.4 -3.4 -6.6 -9.5 -10.9 -28.6 -20.2 -21.5 -10.4 -27.5 -15.1 -32.7 -25.7 -3.1 -6.3 -3.3 -7.2 -3.3 -17.7 0.1 -9.1 0.5 -12 2.4 -16.8 5.3 -13.4 16.5 -23.3 31.5 -27.9 5.6 -1.7 8.6 -2 16.7 -1.6 8.9 0.4 10.7 0.9 17.4 4.2 8.9 4.4 17.2 12.1 20.9 19.4 1.4 2.8 2.6 5.6 2.6 6.1 0 0.9 -27.9 15.6 -28.4 14.9 -0.2 -0.2 -1.4 -2 -2.8 -4.1 -5.3 -7.9 -13.3 -11.2 -20.2 -8.3 -4 1.7 -7.6 6.8 -7.6 10.9 0 6.9 5.4 11.8 20.3 18.4 18 7.9 32.9 16.8 39.6 23.4 1.8 1.9 4.7 6.3 6.4 9.9 2.7 5.6 3.2 7.9 3.5 16.2 0.5 11.8 -1.7 20.3 -7.6 29.3 -7.6 11.7 -18.3 19.3 -32.2 23 -6.2 1.7 -25.4 1.9 -31 0.4z"></path>
<path d="M1118 271 c-17.1 -4.3 -27.7 -10.6 -40.6 -24.3 -5.2 -5.4 -8.2 -9.8 -12.2 -17.7 -6.9 -13.9 -8.4 -19.7 -8.9 -36 -0.6 -16.4 0.9 -24.3 6.6 -36.6 5.5 -11.7 11.7 -20 20.5 -27.7 9.2 -8.1 17.3 -12.6 29.6 -16.8 8 -2.7 11.4 -3.3 21.9 -3.7 17.7 -0.7 28.4 1.5 43.8 9 9.7 4.7 14.7 8.7 24 19.1 14.8 16.5 19.6 29.6 19.7 54.2 0 12.8 -0.3 16.2 -2.3 23.5 -3.4 12.4 -9.3 23 -18 32.2 -12.8 13.7 -23.3 19.9 -41 24.4 -12.1 3.1 -31.5 3.3 -43.1 0.4z m32.9 -30.1 c8.9 -1.6 14.3 -4.2 21.1 -10.5 10.4 -9.7 15.3 -22.3 15.3 -39.4 0 -22.3 -9.5 -39.2 -26.6 -47.1 -6.5 -3 -8.3 -3.3 -18.3 -3.7 -17 -0.7 -27.7 3.1 -37.1 13.1 -8.5 8.9 -13.3 22.2 -13.3 36.8 -0.1 36.5 23.6 56.8 58.9 50.8z"></path>
<path d="M116.7 259.8 c-21.5 -21.4 -40.1 -47.4 -49.3 -69 -1.9 -4.5 -3.3 -8.2 -3.2 -8.3 0.2 -0.2 6.4 1.9 13.8 4.6 39.7 14.5 52.8 20.7 56.3 26.6 2.3 4 2.4 9.6 0.2 14.8 l-1.8 4 -1.2 -4.8 c-1.6 -6.3 -7.9 -12.8 -16.1 -16.7 -5.8 -2.8 -22.3 -7.4 -23.2 -6.5 -0.8 0.7 20.8 30.1 29.1 39.6 l4.9 5.6 7.6 -4.1 c16.5 -8.9 28.7 -25.3 31.8 -42.6 3.5 -20.6 -2.9 -41.1 -18.1 -56.9 -12.9 -13.5 -24.5 -20.2 -49.7 -28.9 -17.7 -6.1 -23.4 -8.5 -31.3 -13.1 -20.4 -11.6 -34.4 -28.2 -39 -46.2 -2 -7.5 -2 -20.9 -0.2 -28.9 l1.3 -5.5 0.8 6.5 c2.4 21.7 11.4 39 26.7 51.6 9.4 7.7 18.7 12.1 44.4 20.9 58.6 20.2 75.6 34.1 85.1 69.2 3.7 13.8 4 33.3 0.6 44.1 -6.8 21.5 -25.1 39.9 -49.2 49.4 -11.5 4.6 -9.9 5 -20.3 -5.4z"></path>
<path d="M441 190.5 l0 -78.5 17.5 0 17.5 0 0 78.5 0 78.5 -17.5 0 -17.5 0 0 -78.5z"></path>
<path d="M858 190.5 l0 -78.5 18 0 18 0 0 78.5 0 78.5 -18 0 -18 0 0 -78.5z"></path>
<path d="M942 190.5 l0 -78.5 18 0 18 0 0 7.1 0 7.2 4.5 -4.2 c6.7 -6.2 15.9 -11.7 21.6 -13.1 8.5 -2.1 21 -0.8 29.9 2.9 4.1 1.7 8.1 3.5 8.8 4 1.1 0.6 -0.4 4.3 -6.3 16.2 -4.3 8.5 -7.9 15.6 -8.1 15.8 -0.2 0.2 -3.2 -0.9 -6.6 -2.5 -5.3 -2.4 -7.6 -2.9 -14.3 -2.9 -7 0 -8.7 0.4 -13.4 3 -6.6 3.7 -10.4 8.2 -13.3 16 -2.3 5.9 -2.3 6.9 -2.6 56.8 l-0.3 50.7 -17.9 0 -18 0 0 -78.5z"></path>
<path d="M145 191.5 c-7.1 -7.2 -17 -14 -29.8 -20.4 -10.1 -5.1 -33.5 -13.6 -44.2 -16.1 -13.5 -3.2 -32.8 -13.7 -42 -23 -6.9 -6.8 -13.5 -17.3 -16.6 -26.6 -2.3 -6.6 -2.7 -9.7 -2.8 -18.9 -0.1 -11.4 1.1 -23.2 2.2 -22 0.4 0.3 1.4 4.6 2.3 9.4 3.6 18.6 10.6 32 23.8 45.2 11.8 11.7 18.1 15.2 39.9 21.9 25.8 8 39.3 14.5 53.6 26.1 10 8 20.9 24.4 19.4 28.9 -0.2 0.6 -2.8 -1.5 -5.8 -4.5z"></path>
<path d="M240 182.6 c0 -2.9 4.2 -12.6 7.5 -17.1 7.7 -10.9 17.3 -18.4 40 -31.2 18.3 -10.3 23.6 -14.3 37.8 -28.2 l11.7 -11.6 0 3.5 c0 10 -5.7 21.6 -15.1 31.1 -7.3 7.4 -13.7 11.2 -32.1 19.3 -21.6 9.6 -32.7 16.6 -43 27.4 -3.8 3.8 -6.8 6.9 -6.8 6.8z"></path>
<path d="M244 145.8 c0 -3.2 4.3 -15.5 7.8 -22.2 4.1 -7.9 14.2 -18.7 22.2 -23.8 3 -2 11.6 -6.7 19 -10.7 16.7 -8.8 31.3 -19.6 44.9 -33.2 l10.4 -10.3 -0.6 4.2 c-3.3 20.1 -19.8 37.3 -50.7 52.7 -6.3 3.2 -14 7.5 -17.2 9.6 -5.9 4 -25.8 23.1 -32.2 30.8 -2.1 2.6 -3.6 3.8 -3.6 2.9z"></path>
<path d="M182.1 139.6 c-6.5 -8.4 -21.1 -21.9 -26.3 -24.3 -4.1 -2 -5 -3 -8.2 -9.6 -5 -10.4 -15.6 -21.6 -24.4 -25.9 -6.4 -3.1 -7.3 -3.3 -18.3 -3.3 -13.8 0 -15.9 1 -15.9 7.8 0 3.6 -0.2 3.8 -1.7 2.6 -3 -2.5 -7.3 -10.2 -7.3 -13.2 0 -9.4 12.7 -18.9 29.4 -21.8 5.5 -1 8.2 -2.1 12.1 -5.1 7.3 -5.6 13.7 -7.2 26.5 -6.6 13.4 0.7 20.2 3 46.3 15.4 22.9 11 24.1 11.5 28.5 12.3 l3.2 0.6 -3.6 5 c-9.8 13.7 -18.1 38.4 -19.6 58.5 -0.5 5.9 -2.8 -13.8 -2.8 -23.7 0 -9.8 1.9 -21.5 4.4 -27.5 0.9 -2.1 1.6 -4 1.6 -4.3 0 -0.2 -4.2 -2.4 -9.2 -4.8 -5.1 -2.4 -13.3 -7 -18.3 -10.1 -15.3 -9.7 -33.9 -13.8 -42 -9.4 l-3 1.6 5 0.7 c6.9 0.9 18.2 4.3 19.1 5.7 0.5 0.8 0.1 0.9 -1.1 0.4 -1.1 -0.4 -10.7 -1 -21.4 -1.3 -21 -0.6 -29.5 0.3 -32.5 3.6 -1.6 1.7 -1.3 1.8 5.3 2.5 13.2 1.2 28 7.2 39.8 16 11.7 8.9 21.8 21.8 30.1 38.7 4.1 8.5 9.7 23.8 8.9 24.5 -0.2 0.3 -2.3 -2 -4.6 -5z"></path>
<path d="M57.1 65.6 l-6.4 -6.4 2.9 -12.2 2.9 -12.3 11 -3.9 c56.8 -20.4 121.7 -24.1 184 -10.6 12 2.6 32.2 8.6 36.2 10.7 0.7 0.4 -3.1 2.5 -8.8 5 l-10 4.4 -7.4 -2.2 c-10.1 -2.9 -23.7 -5.6 -38.6 -7.7 -16.6 -2.4 -59.3 -2.4 -79.4 0 -26.3 3 -71.7 12.6 -73.4 15.5 -0.4 0.6 -1.8 6.8 -3.1 13.6 -1.3 6.9 -2.6 12.5 -3 12.5 -0.3 0 -3.4 -2.9 -6.9 -6.4z"></path>
<path d="M449.3 66.9 c-12.3 -6.1 -17 -20.9 -10.4 -32.4 5.2 -9 12.9 -12.5 24.6 -11 6.5 0.8 11.1 4.1 14.9 10.9 11 19 -9.7 42.1 -29.1 32.5z"></path>
<path d="M867.5 67.2 c-5 -2.3 -10.3 -7.6 -12.1 -11.9 -1.8 -4.3 -1.8 -15.2 0.1 -19.6 2.2 -5.4 9.8 -11.5 15.2 -12.3 6.4 -0.9 13.9 0.2 17.9 2.7 7.6 4.7 12.7 16.5 10.5 24.5 -1.5 5.4 -6.1 11.7 -11.2 15.1 -5.4 3.6 -14.5 4.3 -20.4 1.5z"></path>
</g>
</symbol>
</defs>
<use href="#iosiro-logo"></use>
</svg>
<div class="page-header" id="page-header">
<svg version="1.0">
<use href="#iosiro-logo"></use>
</svg>
</div>
<main class="report-main">
<svg version="1.0" class="frontpage-logo">
<use href="#iosiro-logo"></use>
</svg>
<div class="frontpage-title">CoverProducts refactor and Total Active Cover fix</div>
<div class="frontpage-subtitle">Nexus Mutual, 15 July 2024</div>
<nav class="toc">
<h1>Contents</h1>
<ul>
<li>
<a href="#introduction">Introduction</a></li>
<li>
<a href="#disclaimer">Disclaimer</a></li>
<li>
<a href="#methodology">Methodology</a></li>
<li>
<a href="#audit-findings">Audit findings</a><ul>
<li>
<a href="#io-nxm-cp-001-incorrect-address">IO-NXM-CP-001 Incorrect address</a></li>
<li>
<a href="#io-nxm-cp-002-validation-of-zero-pool">IO-NXM-CP-002 Validation of zero pool</a></li>
<li>
<a href="#io-nxm-cp-003-define-constant-using-dependent-constants">IO-NXM-CP-003 Define constant using dependent constants</a></li>
</ul>
</li>
<li>
<a href="#code-quality-improvement-suggestions">Code quality improvement suggestions</a></li>
<li>
<a href="#specification">Specification</a><ul>
<li>
<a href="#refactor">Refactor</a></li>
<li>
<a href="#incorrect-active-cover-accounting-fix">Incorrect Active Cover Accounting Fix</a></li>
</ul>
</li>
<li>
<a href="#test-coverage-report">Test coverage report</a></li>
</ul>
</nav>
<article class="report">
<h1 id="introduction">Introduction</h1>
<p>iosiro was commissioned by Nexus Mutual to perform a smart contract audit of a bug fix for the total active cover per cover asset logic and various other refactoring changes made to avoid contract size limits. One auditor conducted the audit between 9 July 2024 and 15 July 2025, using 4 audit days.</p>
<h4 id="overview">Overview</h4>
<p>The audit uncovered no critical, high, or medium risk issues. Two low risk issues were found and reported, and both were remediated during the audit. Several code quality improvement suggestions were also made. A breakdown of the issues reported and their status at the conclusion of the audit is provided below:</p>
<table class="findings-count">
<thead>
<tr>
<th> </th>
<th>Critical</th>
<th>High</th>
<th>Medium</th>
<th>Low</th>
<th>Informational</th>
</tr>
</thead>
<tbody>
<tr>
<td>Open</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>Resolved</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>2</td>
<td>1</td>
</tr>
<tr>
<td>Closed</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<hr/>
<h4 id="scope">Scope</h4>
<p>The assessment focused on source file listed below, with all other files considered out of scope. Any out-of-scope code interacting with the assessed code was presumed to operate correctly without introducing functional or security vulnerabilities.</p>
<ul>
<li><strong>Project name:</strong> Nexus Mutual</li>
<li><strong>Initial audit commit:</strong> <a href="https://github.com/NexusMutual/smart-contracts/tree/9a516f8970a16137f169f9fe8f8571734ac37c3b">9a516f8</a></li>
<li><strong>Final review commit:</strong> <a href="https://github.com/NexusMutual/smart-contracts/tree/00a844d746d27542e634de6cc457392fd137f8d9">00a844d</a></li>
<li><strong>Files:</strong> <br/><code>contracts/modules/cover/Cover.sol</code>, <br/><code>contracts/modules/cover/CoverNFTDescriptor.sol</code>, <br/><code>contracts/modules/staking/StakingPool.sol</code>, <br/><code>contracts/modules/staking/StakingProducts.sol</code>, <br/><code>contracts/modules/assessment/IndividualClaims.sol</code>, <br/><code>contracts/modules/assessment/YieldTokenIncidents.sol</code></li>
</ul>
<p>A specification is available in the <a href="#specification">Specification section</a> of this report.</p>
<h1 id="disclaimer">Disclaimer</h1>
<p>This report aims to provide an overview of the assessed smart contracts' risk exposure and a guide to improving their security posture by addressing identified issues. The audit, limited to specific source code at the time of review, sought to:</p>
<ul>
<li>Identify potential security flaws.</li>
<li>Verify that the smart contracts' functionality aligns with their documentation.</li>
</ul>
<p>Off-chain components, such as backend web application code, keeper functionality, and deployment scripts were explicitly not in-scope of this audit.</p>
<p>Given the unregulated nature and ease of cryptocurrency transfers, operations involving these assets face a high risk from cyber attacks. Maintaining the highest security level is crucial, necessitating a proactive and adaptive approach that accounts for the experimental and rapidly evolving nature of blockchain technology. To encourage secure code development, developers should:</p>
<ul>
<li>Integrate security throughout the development lifecycle.</li>
<li>Employ defensive programming to mitigate the risks posed by unexpected events.</li>
<li>Adhere to current best practices wherever possible.</li>
</ul>
<h1 id="methodology">Methodology</h1>
<p>The audit was conducted using the techniques described below.</p>
<dl>
<dt>Code review</dt>
<dd>The source code was manually inspected to identify potential security flaws. Code review is a useful approach for detecting security flaws, discrepancies between the specification and implementation, design improvements, and high-risk areas of the system.</dd>
<dt>Dynamic analysis</dt>
<dd>The contracts were compiled, deployed, and tested in a test environment, both manually and through the test suite provided. Dynamic analysis was used to identify additional edge cases, confirm that the code was functional, and to validate the reported issues.</dd>
<dt>Automated analysis</dt>
<dd>Automated tooling was used to detect the presence of various types of security vulnerabilities. Static analysis results were reviewed manually and any false positives were removed. Any true positive results are included in this report.</dd>
</dl>
<h1 id="audit-findings">Audit findings</h1>
<p>The table below provides an overview of the audit's findings. Detailed write-ups are provided below.</p>
<table class="findings">
<thead>
<tr>
<th>ID</th>
<th>Issue</th>
<th>Risk</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="#IO-NXM-CP-001">IO-NXM-CP-001</a></td>
<td>Incorrect address</td>
<td class="rating-low">Low</td>
<td class="status-resolved">Resolved</td>
</tr>
<tr>
<td><a href="#IO-NXM-CP-002">IO-NXM-CP-002</a></td>
<td>Validation of zero pool</td>
<td class="rating-low">Low</td>
<td class="status-resolved">Resolved</td>
</tr>
<tr>
<td><a href="#IO-NXM-CP-003">IO-NXM-CP-003</a></td>
<td>Define constant using dependent constants</td>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
</tr>
</tbody>
</table>
<p>Each issue identified during the audit has been assigned a risk rating. The rating is determined based on the criteria outlined below.</p>
<dl>
<dt>Critical risk</dt>
<dd>The issue could result in the theft of funds from the contract or its users.</dd>
<dt>High risk</dt>
<dd>The issue could result in the loss of funds for the contract owner or its users.</dd>
<dt>Medium risk</dt>
<dd>The issue resulted in the code being dysfunctional or the specification being implemented incorrectly.</dd>
<dt>Low risk</dt>
<dd>A design or best practice issue that could affect the ordinary functioning of the contract.</dd>
<dt>Informational</dt>
<dd>An improvement related to best practice or a suboptimal design pattern.</dd>
</dl>
<p>In addition to a risk rating, each issue is assigned a status:</p>
<dl>
<dt>Open</dt>
<dd>The issue remained present in the code as of the final commit reviewed and may still pose a risk.</dd>
<dt>Resolved</dt>
<dd>The issue was identified during the audit and has since been satisfactorily addressed, removing the risk it posed.</dd>
<dt>Closed</dt>
<dd>The issue was identified during the audit and acknowledged by the developers as an acceptable risk without actioning any change.</dd>
</dl>
<a name="IO-NXM-CP-001"></a><h2 id="io-nxm-cp-001-incorrect-address" class="break-before"><strong>IO-NXM-CP-001</strong> Incorrect address</h2>
<table class="metadata">
<tbody>
<tr>
<td class="rating-low">Low</td>
<td class="status-resolved">Resolved</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/test/fork/cover-products.js#L321">cover-products.js#L321</a></td>
</tr>
</tbody>
</table>
<p>The fork test provided used an incorrect address when redeploying the <code>StakingProducts.sol</code> contract. This raised a concern that the mainnet deployment of the contracts would leverage the same JavaScript or deployment template, resulting in a misconfiguration.</p>
<p>When upgrading the <code>StakingProducts.sol</code> contract, the fork test incorrectly used the new implementation address of the <code>Cover.sol</code> contract instead of the existing proxy address. This misconfiguration was not self-evident, as the <code>StakingProducts.sol</code> contract only retrieved <code>constant</code> values from the <code>Cover.sol</code> contract. Future updates to the <code>Cover.sol</code> contract, particularly the <code>constants</code> defined therein, would not propagate to the <code>StakingProducts.sol</code> contract, which could result in undesired behaviour.</p>
<h3 id="recommendation">Recommendation</h3>
<p>The correct addresses should be passed in the fork test. However, more importantly, it should be confirmed that the same issue is not present in the deployment scripts.</p>
<h3 id="client-response">Client response</h3>
<p>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commits/68e3f782c0397853ea64e8cbb02d50acf6c30884">68e3f78</a>.</p>
<a name="IO-NXM-CP-002"></a><h2 id="io-nxm-cp-002-validation-of-zero-pool" class="break-before"><strong>IO-NXM-CP-002</strong> Validation of zero pool</h2>
<table class="metadata">
<tbody>
<tr>
<td class="rating-low">Low</td>
<td class="status-resolved">Resolved</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/cover/CoverProducts.sol#L209">CoverProducts.sol#L209</a></td>
</tr>
</tbody>
</table>
<p>A cover product's allow list can include the zero pool, which cannot exist. The <code>CoverProducts::setProducts(...)</code> function aims to prevent setting an allow list that includes non-existent pools; however, this validation fails to check for the zero pool ID.</p>
<p>The source code for the validations performed on the allow list is given below for reference:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="err">#</span> <span class="n">CoverProducts</span><span class="p">.</span><span class="n">sol</span><span class="err">#</span><span class="n">L209</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">param</span><span class="p">.</span><span class="n">allowedPools</span><span class="p">.</span><span class="n">length</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">uint</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o"><</span> <span class="n">param</span><span class="p">.</span><span class="n">allowedPools</span><span class="p">.</span><span class="n">length</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">param</span><span class="p">.</span><span class="n">allowedPools</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">></span> <span class="n">poolCount</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">revert</span> <span class="n">StakingPoolDoesNotExist</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre><p>When creating a pool, the number of pools is pre-incremented and returned as the new pool's ID. As evident from the following <a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/staking/StakingPoolFactory.sol#L35">code</a> extract from <code>StakingPoolFactory::create(...)</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">function</span> <span class="nf">create</span><span class="p">(</span><span class="kt">address</span> <span class="n">_beacon</span><span class="p">)</span> <span class="k">external</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">uint</span> <span class="n">poolId</span><span class="p">,</span> <span class="kt">address</span> <span class="n">stakingPoolAddress</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">require</span><span class="p">(</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span> <span class="o">==</span> <span class="n">operator</span><span class="p">,</span> <span class="s">"StakingPoolFactory: Not operator"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">beacon</span> <span class="o">=</span> <span class="n">_beacon</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">poolId</span> <span class="o">=</span> <span class="o">++</span><span class="n">_stakingPoolCount</span><span class="p">;</span>
</span></span></code></pre><p>The following proof of concept was developed to validate the presence of the issue:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">test</span><span class="o">/</span><span class="n">unit</span><span class="o">/</span><span class="n">CoverProducts</span><span class="o">/</span><span class="n">setProducts</span><span class="p">.</span><span class="n">js</span> <span class="n">b</span><span class="o">/</span><span class="n">test</span><span class="o">/</span><span class="n">unit</span><span class="o">/</span><span class="n">CoverProducts</span><span class="o">/</span><span class="n">setProducts</span><span class="p">.</span><span class="n">js</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="mi">453257</span><span class="n">e1</span><span class="p">..</span><span class="n">eb02cc59</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">test</span><span class="o">/</span><span class="n">unit</span><span class="o">/</span><span class="n">CoverProducts</span><span class="o">/</span><span class="n">setProducts</span><span class="p">.</span><span class="n">js</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">test</span><span class="o">/</span><span class="n">unit</span><span class="o">/</span><span class="n">CoverProducts</span><span class="o">/</span><span class="n">setProducts</span><span class="p">.</span><span class="n">js</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">178</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">178</span><span class="p">,</span><span class="mi">17</span> <span class="err">@@</span> <span class="n">describe</span><span class="p">(</span><span class="s">'setProducts'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="n">it</span><span class="p">(</span><span class="s">'should revert if trying to add a product with zero as poolId in allowedPools'</span><span class="p">,</span> <span class="n">async</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="n">const</span> <span class="n">fixture</span> <span class="o">=</span> <span class="n">await</span> <span class="n">loadFixture</span><span class="p">(</span><span class="n">setup</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="n">const</span> <span class="p">{</span> <span class="n">coverProducts</span> <span class="p">}</span> <span class="o">=</span> <span class="n">fixture</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="n">const</span> <span class="p">[</span><span class="n">advisoryBoardMember0</span><span class="p">]</span> <span class="o">=</span> <span class="n">fixture</span><span class="p">.</span><span class="n">accounts</span><span class="p">.</span><span class="n">advisoryBoardMembers</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="n">const</span> <span class="n">productParams</span> <span class="o">=</span> <span class="p">{</span> <span class="p">...</span><span class="n">productParamsTemplate</span><span class="p">,</span> <span class="n">allowedPools</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="n">await</span> <span class="n">expect</span><span class="p">(</span><span class="n">coverProducts</span><span class="p">.</span><span class="n">connect</span><span class="p">(</span><span class="n">advisoryBoardMember0</span><span class="p">).</span><span class="n">setProducts</span><span class="p">([</span><span class="n">productParams</span><span class="p">])).</span><span class="n">to</span><span class="p">.</span><span class="n">revertedWithCustomError</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="n">coverProducts</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="s">'StakingPoolDoesNotExist'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"> <span class="n">it</span><span class="p">(</span><span class="s">'should revert if trying to edit a non-existing product'</span><span class="p">,</span> <span class="n">async</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">const</span> <span class="n">fixture</span> <span class="o">=</span> <span class="n">await</span> <span class="n">loadFixture</span><span class="p">(</span><span class="n">setup</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">const</span> <span class="p">{</span> <span class="n">coverProducts</span> <span class="p">}</span> <span class="o">=</span> <span class="n">fixture</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span></code></pre><h3 id="recommendation-1">Recommendation</h3>
<p>The validation performed in <code>CoverProducts::setProducts(...)</code> should be expanded to prevent specifying <code>0</code> as a pool ID, e.g.</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">param</span><span class="p">.</span><span class="n">allowedPools</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">></span> <span class="n">poolCount</span> <span class="o">||</span> <span class="n">param</span><span class="p">.</span><span class="n">allowedPools</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span></code></pre><h3 id="client-response-1">Client response</h3>
<p>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commit/390a38803b5fbf86517e0320e93c1e7637a25b20">390a388</a>.</p>
<a name="IO-NXM-CP-003"></a><h2 id="io-nxm-cp-003-define-constant-using-dependent-constants" class="break-before"><strong>IO-NXM-CP-003</strong> Define constant using dependent constants</h2>
<table class="metadata">
<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/cover/Cover.sol#L619">Cover.sol#L619</a></td>
</tr>
</tbody>
</table>
<p>The number of buckets to search ahead when recalculating total active cover is hardcoded to <code>53</code>. If either the size of the buckets or the maximum cover period is to change in the future, failing to update the <code>yearlyBucketsCount</code> could result in a significant miscalculation of total active cover. Since <code>yearlyBucketsCount</code> is defined as a hardcoded inline value and not alongside other constants, this increases the likelihood that it could be overlooked.</p>
<h3 id="recommendation-2">Recommendation</h3>
<p>The value for <code>yearlyBucketsCount</code> should be defined as a smart contract constant using <code>Math.divCeil(MAX_COVER_PERIOD, BUCKET_SIZE)</code> to ensure that if <code>MAX_COVER_PERIOD</code> or <code>BUCKET_SIZE</code> is updated that <code>yearlyBucketsCount</code> is not overlooked. At a minimum, the fixed value should be defined as a constant at the contract level, not as a hardcoded inline value.</p>
<h3 id="client-response-2">Client response</h3>
<p>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commit/6d03da4e9963dcc24366d74ec9eadad76092d1f5">6d03da4</a>.</p>
<h1 id="code-quality-improvement-suggestions">Code quality improvement suggestions</h1>
<p>Code improvement suggestions without security implications are listed below.</p>
<table class="codequality">
<thead>
<tr>
<th>#</th>
<th>Location</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/assessment/YieldTokenIncidents.sol#L136">YieldTokenIncidents.sol#L136</a></td>
<td>Use <code>getProductWithType(...)</code> instead of <code>getProduct(...)</code> and <code>getProductType(...)</code> to reduce number of cross contract calls and gas overheads.</td>
</tr>
<tr>
<td>2</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/cover/Cover.sol#L60">Cover.sol#L60</a></td>
<td><code>PRICE_DENOMINATOR</code>, <code>CAPACITY_REDUCTION_DENOMINATOR</code>, <code>REWARD_DENOMINATOR</code> and <code>ONE_YEAR</code> are unused in the <code>Cover</code> contract and can be removed.</td>
</tr>
<tr>
<td>3</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/cover/Cover.sol#L626">Cover.sol#L626</a></td>
<td>Store changes using a single <code>SSTORE</code> when updating <code>activeCover[coverAsset]})</code>, e.g. <code>activeCover[coverAsset] = ActiveCover({totalActiveCoverInAsset: totalActiveCover.toUint192(), lastBucketUpdateId: currentBucketId.toUint64()});</code>.</td>
</tr>
<tr>
<td>4</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/cover/Cover.sol#L243">Cover.sol#L243</a></td>
<td>Validation of the <code>paymentAsset</code> should be performed earlier to reduce the gas cost of reverted transactions that specify an invalid <code>paymentAsset</code>. Validations that can be considered <code>pure</code> should be performed prior to validations that require storage access.</td>
</tr>
<tr>
<td>5</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/cover/CoverProducts.sol#L225">CoverProducts.sol#L225</a></td>
<td>Move validation to earlier in the for loop to reduce gas cost of when reverting due to an incorrect <code>productId</code>. Validations that can be considered <code>pure</code> should be performed prior to validations that require storage access.</td>
</tr>
<tr>
<td>6</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/cover/CoverProducts.sol#L362">CoverProducts.sol#L362</a></td>
<td>The <code>CoverProducts</code> contract does not need to resolve and store a reference to itself in <code>internalContracts</code>.</td>
</tr>
<tr>
<td>7</td>
<td><a href="https://github.com/NexusMutual/smart-contracts/blob/9a516f8970a16137f169f9fe8f8571734ac37c3b/contracts/modules/cover/CoverProducts.sol#L25">CoverProducts.sol#L25</a></td>
<td><code>CoverProducts</code> has <code>productNames(...)</code> exposed using the <code>public</code> access modifier as well as the <code>getProductNames(...)</code> function. These two functions are identical. <code>productNames(...)</code> should be marked as <code>internal</code> to match the getter pattern used for all other storage variables in the contract.</td>
</tr>
</tbody>
</table>
<h3 id="client-response-3">Client response</h3>
<ol>
<li>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commit/4aa3afbf074092fdbd677f2ba631dcc472f406f2">4aa3afb</a>.</li>
<li>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commit/2240cee1b1672595b7b287fb9088d0e3180ba490">2240cee</a>.</li>
<li>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commit/4aa3afbf074092fdbd677f2ba631dcc472f406f2">4aa3afb</a>.</li>
<li>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commit/4aa3afbf074092fdbd677f2ba631dcc472f406f2">4aa3afb</a>.</li>
<li>Won't fix.</li>
<li>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commit/4aa3afbf074092fdbd677f2ba631dcc472f406f2">4aa3afb</a>.</li>
<li>Fixed in <a href="https://github.com/NexusMutual/smart-contracts/commit/7e3626641e85d11285382365291925c1df2eb3ec">7e36266</a>.</li>
</ol>
<h1 id="specification">Specification</h1>
<p>The following section outlines the system's intended functionality at a high level based on its implementation in the codebase. Any perceived points of conflict should be highlighted with the auditing team to determine the source of the discrepancy.</p>
<h2 id="refactor">Refactor</h2>
<p>Nexus Mutual performed a refactor of their protocol contracts. This was necessary as the existing <code>Cover.sol</code> contract was approaching the EVM contract size limit. The contract size limit hindered the implementation of additional functionality and bug fixes.</p>
<h3 id="cover-refactor">Cover Refactor</h3>
<p>The <code>Cover.sol</code> contract was modified to remove the logic of managing cover products and staking pools. This logic and related view functions were migrated to other contracts. As such, <code>Cover.sol</code> is now primarily responsible for the lifecycle management of covers by exposing an interface that allows the buying and expiring of covers. Care was taken to ensure the refactor maintains the contract's storage layout.</p>
<h3 id="cover-products-refactor">Cover Products Refactor</h3>
<p>A new contract, <code>CoverProducts.sol</code> was added to house the Cover products lifecycle management logic. This included logic to set and view product and product types previously in <code>Cover.sol</code> and helper functions such as checking whether a pool is authorized to have a product or getting capacity reduction ratios for a set of products. A migration function was also added to facilitate the migration of product-related data from the existing <code>Cover.sol</code> contract to this new contract. Finally, functionality to set and view Product and Product Type metadata was added to allow easier retrieval from the front end instead of the existing pattern that relied on reading contract events.</p>
<h3 id="staking-products-refactor">Staking Products Refactor</h3>
<p>The logic to create new staking pools and related view functions was migrated from <code>Cover.sol</code> to the <code>StakingProducts.sol</code> contract.</p>
<h3 id="other-contract-changes">Other Contract Changes</h3>
<p>Other protocol contracts contained minor changes to account for the refactored contracts, e.g., changing instances where <code>Cover</code> was used for interfacing with product-related logic to now use the <code>CoverProducts.sol</code> contract. Additionally, legacy contracts such as <code>LegacyGateway.sol</code>, <code>PricesV1.sol</code>, and <code>ProductsV1.sol</code> were removed.</p>
<h2 id="incorrect-active-cover-accounting-fix">Incorrect Active Cover Accounting Fix</h2>
<p>The refactor allowed Nexus Mutual to implement a complete fix for the active cover accounting issue that was patched in January <a href="https://github.com/NexusMutual/smart-contracts/pull/1041/files">[PR 1041]</a>. This fix was applied in <code>Cover.sol</code> and involved deducting the cover amount from the active cover for the cover asset and deducting it from the expiry bucket if the cover was expiring in the future. Additionally, a new <code>recalculateActiveCoverInAsset()</code> function was added to reset and recalculate the total active cover for an asset based on it's expiration buckets. This function will allow the correction of the current on-chain active cover values.</p>
<h1 id="test-coverage-report">Test coverage report</h1>
<p>The coverage report of the provided tests on the final day of the audit is given below.</p>
<table>
<thead>
<tr>
<th>File</th>
<th>% Stmts</th>
<th>% Branch</th>
<th>% Funcs</th>
<th>% Lines</th>
</tr>
</thead>
<tbody>
<tr>
<td>assessment/</td>
<td>99.43</td>
<td>97.02</td>
<td>95.83</td>
<td>99.46</td>
</tr>
<tr>
<td>Assessment.sol</td>
<td>100</td>
<td>98.39</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>IndividualClaims.sol</td>
<td>99.19</td>
<td>98.33</td>
<td>93.75</td>
<td>99.22</td>
</tr>
<tr>
<td>YieldTokenIncidents.sol</td>
<td>99.02</td>
<td>93.48</td>
<td>92.86</td>
<td>99.07</td>
</tr>
<tr>
<td>capital/</td>
<td>99.18</td>
<td>90.49</td>
<td>96.8</td>
<td>97.86</td>
</tr>
<tr>
<td>MCR.sol</td>
<td>97.33</td>
<td>88.46</td>
<td>92.86</td>
<td>97.26</td>
</tr>
<tr>
<td>Pool.sol</td>
<td>98.37</td>
<td>86.76</td>
<td>96.55</td>
<td>97.66</td>
</tr>
<tr>
<td>PriceFeedOracle.sol</td>
<td>100</td>
<td>78.57</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>Ramm.sol</td>
<td>100</td>
<td>100</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>SafeTracker.sol</td>
<td>97.3</td>
<td>90</td>
<td>92.31</td>
<td>97.44</td>
</tr>
<tr>
<td>SwapOperator.sol</td>
<td>99.55</td>
<td>90</td>
<td>96.77</td>
<td>95.85</td>
</tr>
<tr>
<td>cover/</td>
<td>93.09</td>
<td>82.94</td>
<td>90.36</td>
<td>90.91</td>
</tr>
<tr>
<td>Cover.sol</td>
<td>90.53</td>
<td>80.3</td>
<td>90</td>
<td>88.32</td>
</tr>
<tr>
<td>CoverNFT.sol</td>
<td>84.21</td>
<td>61.54</td>
<td>76.47</td>
<td>81.25</td>
</tr>
<tr>
<td>CoverNFTDescriptor.sol</td>
<td>94.29</td>
<td>80</td>
<td>100</td>
<td>94.12</td>
</tr>
<tr>
<td>CoverProducts.sol</td>
<td>98.59</td>
<td>94.12</td>
<td>96.55</td>
<td>96.39</td>
</tr>
<tr>
<td>governance/</td>
<td>71.36</td>
<td>60.06</td>
<td>78.26</td>
<td>70.53</td>
</tr>
<tr>
<td>Governance.sol</td>
<td>59.51</td>
<td>47.16</td>
<td>71.11</td>
<td>57.86</td>
</tr>
<tr>
<td>MemberRoles.sol</td>
<td>99.33</td>
<td>98.78</td>
<td>100</td>
<td>98.06</td>
</tr>
<tr>
<td>NXMaster.sol</td>
<td>93.14</td>
<td>80.43</td>
<td>84.21</td>
<td>92.59</td>
</tr>
<tr>
<td>ProposalCategory.sol</td>
<td>42.11</td>
<td>22.22</td>
<td>57.14</td>
<td>41.38</td>
</tr>
<tr>
<td>VotePower.sol</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>staking/</td>
<td>98.37</td>
<td>91.04</td>
<td>97.27</td>
<td>97.44</td>
</tr>
<tr>
<td>MinimalBeaconProxy.sol</td>
<td>66.67</td>
<td>100</td>
<td>66.67</td>
<td>66.67</td>
</tr>
<tr>
<td>StakingNFT.sol</td>
<td>97.87</td>
<td>84.38</td>
<td>94.74</td>
<td>94.83</td>
</tr>
<tr>
<td>StakingNFTDescriptor.sol</td>
<td>97.56</td>
<td>83.33</td>
<td>100</td>
<td>97.67</td>
</tr>
<tr>
<td>StakingPool.sol</td>
<td>98.67</td>
<td>92.98</td>
<td>97.62</td>
<td>97.83</td>
</tr>
<tr>
<td>StakingPoolFactory.sol</td>
<td>100</td>
<td>87.5</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>StakingProducts.sol</td>
<td>98.2</td>
<td>92.31</td>
<td>100</td>
<td>97.27</td>
</tr>
<tr>
<td>StakingTypesLib.sol</td>
<td>100</td>
<td>100</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>token/</td>
<td>78.24</td>
<td>65.22</td>
<td>86.96</td>
<td>77.09</td>
</tr>
<tr>
<td>NXMToken.sol</td>
<td>85.94</td>
<td>46.88</td>
<td>87.5</td>
<td>86.36</td>
</tr>
<tr>
<td>TokenController.sol</td>
<td>75</td>
<td>75</td>
<td>86.67</td>
<td>73.29</td>
</tr>
</tbody>
</table>
<p>Overall, the test quality of the smart contracts in scope was found to be comprehensive.</p>
</article>
</main>
</div>
</body></html>