Paravel Citadel DAO Aave Adaptor and Permission Script Smart Contract Audit

<script src="https://cdn.jsdelivr.net/npm/[email protected]/tex-mml-chtml.js" integrity="sha256-vRVWcOQgIgZwqXAy0HojsQITgghn7o9e0qe7KDF/JO8=" crossorigin="anonymous"></script>
<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');.codequality td{min-width:6em;} 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) } .audit-text-formatting .report-main h3{font-size:var(--size-600) }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;font-size:.9em}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:6em;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)}.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:10pt}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:9pt}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}.frontpage-subtitle{page-break-after:always;}.metadata td{padding:.3em}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 [email protected]";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>
<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">Aave Adaptor and Permission Script Smart Contract Audit</div>
<div class="frontpage-subtitle">Paravel, 13 February 2026</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-prv-aps-001-missing-role-capabilities-configuration-for-prvlaaveborrow-adaptor">IO-PRV-APS-001 Missing role capabilities configuration for PrvlAaveBorrow adaptor</a></li>
<li>
<a href="#io-prv-aps-002-removing-token-configuration-clears-approval">IO-PRV-APS-002 Removing token configuration clears approval</a></li>
<li>
<a href="#io-prv-aps-003-quoterexecution-mismatch">IO-PRV-APS-003 Quoter/execution mismatch</a></li>
<li>
<a href="#io-prv-aps-004-weak-slippage-controls">IO-PRV-APS-004 Weak slippage controls</a></li>
<li>
<a href="#io-prv-aps-005-ignored-repay-return-value">IO-PRV-APS-005 Ignored repay return value</a></li>
<li>
<a href="#io-prv-aps-006-missing-safetransferlib-limits-token-compatibility">IO-PRV-APS-006 Missing SafeTransferLib limits token compatibility</a></li>
<li>
<a href="#io-prv-aps-007-missing-quoter-zero-check">IO-PRV-APS-007 Missing quoter zero-check</a></li>
<li>
<a href="#io-prv-aps-008-missing-authority-zero-check">IO-PRV-APS-008 Missing authority zero-check</a></li>
<li>
<a href="#io-prv-aps-009-repay-amountin-not-validated-against-supplyamount">IO-PRV-APS-009 repay() amountIn not validated against supplyAmount</a></li>
<li>
<a href="#io-prv-aps-010-settle-amountin-unknowable-due-to-interest-accrual">IO-PRV-APS-010 settle() amountIn unknowable due to interest accrual</a></li>
<li>
<a href="#io-prv-aps-011-foundry-key-management">IO-PRV-APS-011 Foundry key management</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="#system-architecture">System architecture</a></li>
<li>
<a href="#prvlaaveborrow">PrvlAaveBorrow</a></li>
<li>
<a href="#prvlflashloanaaveborrowv5">PrvlFlashloanAaveBorrowV5</a></li>
<li>
<a href="#permission-scripts">Permission scripts</a></li>
</ul>
</li>
</ul>

</nav>
<article class="report">
<h1 id="introduction">Introduction</h1>
<p>iosiro was commissioned by Paravel to perform a smart contract audit of their Aave V3 leverage adaptor & micro-manager, and associated Foundry permission scripts used to configure vault access control. Two auditors conducted the audit between January 27, 2026, and February 3, 2026, using 10 audit days.</p>
<h4 id="overview">Overview</h4>
<p>Paravel extended the Boring Vault framework into a multi-agent Aave V3 leverage management system with Uniswap V3 swaps and cross-vault fund movement. The audit focused on the contracts and scripts central to this system: the <code>Prvl<wbr/>Aave<wbr/>Borrow</code> adaptor, the legacy <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> micro-manager, and 12 Foundry permission scripts in <code>script/Permissions/</code>.</p>
<p>The audit identified 11 findings: 1 medium, 4 low, and 6 informational-risk, along with 9 code quality improvement suggestions. The most impactful finding was that the <code>Prvl<wbr/>Aave<wbr/>Borrow</code> adaptor was deployed without the necessary role capabilities configured, rendering it unusable by the vault system. Other finding themes included gaps in input validation for numeric parameters, token-handling edge cases, and the maintainability of the permission scripts.</p>
<p>During the audit, Paravel removed the in-scope contracts (<code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol</code> and <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>sol</code>) and associated deployment scripts from the codebase. Leverage management operations (borrow, repay, and settle) are now composed off-chain and submitted directly to the vault via <code>manage<wbr/>Vault<wbr/>With<wbr/>Merkle<wbr/>Verification</code> on <code>Manager<wbr/>With<wbr/>Merkle<wbr/>Verification.<wbr/>sol</code>, with no on-chain adaptor in production. As a result, all medium- and low-risk findings were closed. One informational finding related to the permission scripts remained open at the conclusion of the audit.</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>1</td>
</tr>
<tr>
<td>Resolved</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>Closed</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>4</td>
<td>5</td>
</tr>
</tbody>
</table>
<hr/>
<h4 id="scope">Scope</h4>
<p>The assessment focused on the source files 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> <a href="https://github.com/ParavelDAO/boring-vault">boring-vault</a></li>
<li><strong>Initial audit commit:</strong> <a href="https://github.com/ParavelDAO/boring-vault/commit/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d"><code>b5154a8</code></a></li>
<li><strong>Final review commit:</strong> <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a></li>
<li><strong>Files:</strong> <code>src/adaptors/Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol</code>, <code>src/micro-managers/Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>sol</code>, <code>script/Permissions/*.<wbr/>s.<wbr/>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 and keeper functionality, were explicitly not within the 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, with detailed write-ups in the following sections.</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-PRV-APS-001">IO-PRV-APS-001</a></td>
<td>Missing role capabilities configuration for PrvlAaveBorrow adaptor</td>
<td class="rating-medium">Medium</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-002">IO-PRV-APS-002</a></td>
<td>Removing token configuration clears approval</td>
<td class="rating-low">Low</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-003">IO-PRV-APS-003</a></td>
<td>Quoter/execution mismatch</td>
<td class="rating-low">Low</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-004">IO-PRV-APS-004</a></td>
<td>Weak slippage controls</td>
<td class="rating-low">Low</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-005">IO-PRV-APS-005</a></td>
<td>Ignored repay return value</td>
<td class="rating-low">Low</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-006">IO-PRV-APS-006</a></td>
<td>Missing SafeTransferLib limits token compatibility</td>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-007">IO-PRV-APS-007</a></td>
<td>Missing quoter zero-check</td>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-008">IO-PRV-APS-008</a></td>
<td>Missing authority zero-check</td>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-009">IO-PRV-APS-009</a></td>
<td>repay() amountIn not validated against supplyAmount</td>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-010">IO-PRV-APS-010</a></td>
<td>settle() amountIn unknowable due to interest accrual</td>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-PRV-APS-011">IO-PRV-APS-011</a></td>
<td>Foundry key management</td>
<td class="rating-informational">Informational</td>
<td class="status-open">Open</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-PRV-APS-001"></a><h2 id="io-prv-aps-001-missing-role-capabilities-configuration-for-prvlaaveborrow-adaptor" class="break-before"><strong>IO-PRV-APS-001</strong> Missing role capabilities configuration for PrvlAaveBorrow adaptor</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-medium">Medium</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/DeployPrvlBorrow.s.sol">script/Deploy<wbr/>Prvl<wbr/>Borrow.<wbr/>s.<wbr/>sol</a></td>
</tr>
</tbody>
</table>
<p>The <code>Prvl<wbr/>Aave<wbr/>Borrow</code> adaptor is deployed using <code>Deploy<wbr/>Prvl<wbr/>Borrow.<wbr/>s.<wbr/>sol</code>, but no role capabilities are configured for its vault functions in the deploy script or any other script in the <code>Permissions/</code> directory. The adaptor’s <code>supply()</code>, <code>reduce<wbr/>Position()</code>, and <code>settle()</code> functions are all gated by Solmate’s <code>requires<wbr/>Auth</code> modifier, which checks the <code>Roles<wbr/>Authority</code> contract for role-based access.</p>
<p>Without role capabilities, calls from the vault into the adaptor revert due to missing authorization. The vault is not the owner of the adaptor, and no role has been granted capability to call these functions.</p>
<h3 id="recommendation">Recommendation</h3>
<p>The role capabilities for <code>Prvl<wbr/>Aave<wbr/>Borrow</code> should be configured during deployment or via a dedicated permission script using the following function calls:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">rolesAuthority</span><span class="p">.</span><span class="n">setRoleCapability</span><span class="p">(</span><span class="n">STRATEGIST_ROLE</span><span class="p">,</span> <span class="n">adaptor</span><span class="p">,</span> <span class="n">PrvlAaveBorrow</span><span class="p">.</span><span class="n">supply</span><span class="p">.</span><span class="nb">selector</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">rolesAuthority</span><span class="p">.</span><span class="n">setRoleCapability</span><span class="p">(</span><span class="n">STRATEGIST_ROLE</span><span class="p">,</span> <span class="n">adaptor</span><span class="p">,</span> <span class="n">PrvlAaveBorrow</span><span class="p">.</span><span class="n">reducePosition</span><span class="p">.</span><span class="nb">selector</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">rolesAuthority</span><span class="p">.</span><span class="n">setRoleCapability</span><span class="p">(</span><span class="n">STRATEGIST_ROLE</span><span class="p">,</span> <span class="n">adaptor</span><span class="p">,</span> <span class="n">PrvlAaveBorrow</span><span class="p">.</span><span class="n">settle</span><span class="p">.</span><span class="nb">selector</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">rolesAuthority</span><span class="p">.</span><span class="n">setUserRole</span><span class="p">(</span><span class="n">VAULT</span><span class="p">,</span> <span class="n">STRATEGIST_ROLE</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span></code></pre><p>A distinct adaptor is required for each vault, so this role configuration would need to be applied for each adaptor/vault pair.</p>
<h3 id="client-response">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Aave<wbr/>Borrow</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-002"></a><h2 id="io-prv-aps-002-removing-token-configuration-clears-approval" class="break-before"><strong>IO-PRV-APS-002</strong> Removing token configuration clears approval</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-low">Low</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol#L222">Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol<wbr/>#L222</a></td>
</tr>
</tbody>
</table>
<p><code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>set<wbr/>Token<wbr/>Config()</code> grants token-level approvals from the adaptor to Uniswap and Aave for the configured base and deposit tokens:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">baseToken</span><span class="p">).</span><span class="n">approve</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="n">uniswapV3Router</span><span class="p">),</span> <span class="nb">type</span><span class="p">(</span><span class="nc">uint256</span><span class="p">).</span><span class="nb">max</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">baseToken</span><span class="p">).</span><span class="n">approve</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="n">aave</span><span class="p">),</span> <span class="nb">type</span><span class="p">(</span><span class="nc">uint256</span><span class="p">).</span><span class="nb">max</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">depositToken</span><span class="p">).</span><span class="n">approve</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="n">uniswapV3Router</span><span class="p">),</span> <span class="nb">type</span><span class="p">(</span><span class="nc">uint256</span><span class="p">).</span><span class="nb">max</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">depositToken</span><span class="p">).</span><span class="n">approve</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="n">aave</span><span class="p">),</span> <span class="nb">type</span><span class="p">(</span><span class="nc">uint256</span><span class="p">).</span><span class="nb">max</span><span class="p">);</span>
</span></span></code></pre><p><code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>remove<wbr/>Token<wbr/>Config()</code> then unconditionally zeroes out those same approvals:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">baseToken</span><span class="p">).</span><span class="n">approve</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="n">uniswapV3Router</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">baseToken</span><span class="p">).</span><span class="n">approve</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="n">aave</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">depositToken</span><span class="p">).</span><span class="n">approve</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="n">uniswapV3Router</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">depositToken</span><span class="p">).</span><span class="n">approve</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="n">aave</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span>
</span></span></code></pre><p>If two or more token configurations share the same base or deposit token, removing one configuration clears the approvals required by the other still-active configurations. This would temporarily cause subsequent calls that use the remaining token configs to fail until approvals are restored, e.g., by removing all configs and re-adding the required ones.</p>
<h3 id="recommendation-1">Recommendation</h3>
<p>The potential for this issue should be documented for callers of <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>remove<wbr/>Token<wbr/>Config()</code>. Alternatively, per-token reference counts could be maintained so that approvals are only zeroed when no remaining config needs them.</p>
<h3 id="client-response-1">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Aave<wbr/>Borrow</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-003"></a><h2 id="io-prv-aps-003-quoterexecution-mismatch" class="break-before"><strong>IO-PRV-APS-003</strong> Quoter/execution mismatch</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-low">Low</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/micro-managers/PrvlFlashloanAaveBorrowV5.sol#L203">Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>sol<wbr/>#L203</a></td>
</tr>
</tbody>
</table>
<p>When calling <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>get<wbr/>Borrow<wbr/>User<wbr/>Data()</code>, a swap amount is calculated internally as <code>swap<wbr/>Amount = collateral<wbr/>Amount + borrow<wbr/>Amount</code> and used to obtain a quote from the Uniswap V3 Quoter. However, the actual swap amount encoded in the flashloan callback data is taken from <code>exact<wbr/>Input<wbr/>Params.<wbr/>amount<wbr/>In</code>, which is provided by the caller. These two values are never checked against each other and could differ:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kt">uint256</span> <span class="n">swapAmount</span> <span class="o">=</span> <span class="n">collateralAmount</span> <span class="o">+</span> <span class="n">borrowAmount</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">uint256</span> <span class="n">supplyAmount</span> <span class="o">=</span> <span class="n">quoter</span><span class="p">.</span><span class="n">quoteExactInput</span><span class="p">(</span><span class="n">exactInputParams</span><span class="p">.</span><span class="n">path</span><span class="p">,</span> <span class="n">swapAmount</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">bytes</span> <span class="k">memory</span> <span class="n">swapData</span> <span class="o">=</span> <span class="nb">abi</span><span class="p">.</span><span class="nb">encodeWithSelector</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">EXACT_INPUT_SELECTOR</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">exactInputParams</span>  <span class="c1">// includes amountIn which could differ from swapAmount
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">bytes</span> <span class="k">memory</span> <span class="n">supplyData</span> <span class="o">=</span> <span class="nb">abi</span><span class="p">.</span><span class="nb">encodeWithSelector</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">SUPPLY_SELECTOR</span><span class="p">,</span> <span class="n">depositToken</span><span class="p">,</span> <span class="n">supplyAmount</span><span class="p">,</span> <span class="n">boringVault</span><span class="p">,</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre><p>The <code>supply<wbr/>Amount</code> is quoted using <code>swap<wbr/>Amount</code>, but the actual swap will use <code>exact<wbr/>Input<wbr/>Params.<wbr/>amount<wbr/>In</code>. If <code>amount<wbr/>In < swap<wbr/>Amount</code>, the swap produces less output than <code>supply<wbr/>Amount</code> and the Aave supply reverts. If <code>amount<wbr/>In > swap<wbr/>Amount</code>, extra vault tokens may be consumed silently.</p>
<h3 id="recommendation-2">Recommendation</h3>
<p>The <code>exact<wbr/>Input<wbr/>Params</code> struct may not be necessary as the values could be derived in the function call, saving calldata and mitigating this issue. Alternatively, explicit validation should be added to ensure <code>exact<wbr/>Input<wbr/>Params.<wbr/>amount<wbr/>In</code> equals the computed <code>swap<wbr/>Amount</code>.</p>
<h3 id="client-response-2">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-004"></a><h2 id="io-prv-aps-004-weak-slippage-controls" class="break-before"><strong>IO-PRV-APS-004</strong> Weak slippage controls</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-low">Low</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol#L108">Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol<wbr/>#L108</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol#L138">#L138</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol#L167">#L167</a></td>
</tr>
</tbody>
</table>
<p>The <code>swap<wbr/>Min<wbr/>Out</code> slippage limit in <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>supply()</code>, <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>reduce<wbr/>Position()</code>, and <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>settle()</code> is confirmed to be non-zero, but a value of 1 wei would still be accepted:</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">swapMinOut</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="nb">revert</span> <span class="n">PrvlAaveBorrow__minOutCannotBeZero</span><span class="p">();</span>
</span></span></code></pre><p>A compromised or incorrectly configured strategist could execute swaps with effectively zero slippage protection. Because the Boring Vault’s merkle verification system constrains address arguments but not numeric parameters, the <code>swap<wbr/>Min<wbr/>Out</code> value is entirely under the strategist’s control.</p>
<h3 id="recommendation-3">Recommendation</h3>
<p>The functions should derive a slippage limit value from the swap amount. A slippage tolerance (e.g., 1%) could be configured for the contract and used to calculate a minimum acceptable output based on the swap input amount. This would require an oracle or quoter price for the output token.</p>
<h3 id="client-response-3">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Aave<wbr/>Borrow</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-005"></a><h2 id="io-prv-aps-005-ignored-repay-return-value" class="break-before"><strong>IO-PRV-APS-005</strong> Ignored repay return value</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-low">Low</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol#L143-L145">Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol<wbr/>#L143-L145</a></td>
</tr>
</tbody>
</table>
<p>Both <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>reduce<wbr/>Position()</code> and <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>settle()</code> pull base token from the vault and call <code>aave.<wbr/>repay()</code>, but the contract ignores the returned <code>uint256</code> repaid amount:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">baseToken</span><span class="p">).</span><span class="n">transferFrom</span><span class="p">(</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">,</span> <span class="kt">address</span><span class="p">(</span><span class="nb">this</span><span class="p">),</span> <span class="n">repayAmount</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">aave</span><span class="p">.</span><span class="n">repay</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">baseToken</span><span class="p">,</span> <span class="n">repayAmount</span><span class="p">,</span> <span class="n">config</span><span class="p">.</span><span class="n">aaveVariableRate</span><span class="p">,</span> <span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">);</span>
</span></span></code></pre><p>In Aave V3, <code>repay()</code> returns the actual amount repaid and caps repayment at the outstanding debt. If the caller supplies more than required, the surplus remains in the adaptor instead of being returned to the vault. This breaks the invariant that the adaptor should hold no funds. The stranded tokens would require a separate <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sweep<wbr/>ERC20()</code> call to recover.</p>
<h3 id="recommendation-4">Recommendation</h3>
<p>The amount returned by <code>repay()</code> should be captured, and any excess should be refunded to the vault in the same transaction:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kt">uint256</span> <span class="n">repaid</span> <span class="o">=</span> <span class="n">aave</span><span class="p">.</span><span class="n">repay</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">baseToken</span><span class="p">,</span> <span class="n">repayAmount</span><span class="p">,</span> <span class="n">config</span><span class="p">.</span><span class="n">aaveVariableRate</span><span class="p">,</span> <span class="nb">msg</span><span class="p">.</span><span class="nb">sender</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">repayAmount</span> <span class="o">></span> <span class="n">repaid</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ERC20</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">baseToken</span><span class="p">).</span><span class="nb">transfer</span><span class="p">(</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">,</span> <span class="n">repayAmount</span> <span class="o">-</span> <span class="n">repaid</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre><h3 id="client-response-4">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Aave<wbr/>Borrow</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-006"></a><h2 id="io-prv-aps-006-missing-safetransferlib-limits-token-compatibility" class="break-before"><strong>IO-PRV-APS-006</strong> Missing SafeTransferLib limits token compatibility</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol">Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol</a></td>
</tr>
</tbody>
</table>
<p><code>Prvl<wbr/>Aave<wbr/>Borrow</code> uses Solmate’s <code>ERC20</code> for all <code>transfer</code>, <code>transfer<wbr/>From</code>, and <code>approve</code> calls but does not use <code>Safe<wbr/>Transfer<wbr/>Lib</code>. Solmate’s <code>ERC20</code> ABI-decodes return data as <code>bool</code>, which reverts when a token returns no data (0 bytes). Some ERC-20 tokens, most notably USDT, return <code>void</code> on these functions.</p>
<p>Fork tests confirm all current production tokens (WETH, USDC, wstETH, aWstETH, variableDebtWETH) return <code>bool</code> and work correctly. If a future <code>set<wbr/>Token<wbr/>Config</code> attempts to register a non-standard token, the transaction reverts unconditionally – this is a denial of service (broken config), not a fund-loss vector.</p>
<h3 id="recommendation-5">Recommendation</h3>
<p>The ERC20 return value requirement should be documented on <code>set<wbr/>Token<wbr/>Config</code>. Using <code>Safe<wbr/>Transfer<wbr/>Lib</code> should be considered for forward compatibility.</p>
<h3 id="client-response-5">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Aave<wbr/>Borrow</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-007"></a><h2 id="io-prv-aps-007-missing-quoter-zero-check" class="break-before"><strong>IO-PRV-APS-007</strong> Missing quoter zero-check</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/micro-managers/PrvlFlashloanAaveBorrowV5.sol#L47-L78">Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>sol<wbr/>#L47-L78</a></td>
</tr>
</tbody>
</table>
<p>The <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> constructor validates that all addresses are non-zero except for <code>_<wbr/>quoter</code>. If <code>_<wbr/>quoter</code> is <code>address(0)</code>, the contract deploys successfully but <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>borrow()</code> permanently reverts since it calls <code>quoter.<wbr/>quote<wbr/>Exact<wbr/>Input()</code> in <code>get<wbr/>Borrow<wbr/>User<wbr/>Data()</code>. The <code>repay()</code> and <code>settle()</code> functions still work since <code>get<wbr/>Repay<wbr/>User<wbr/>Data()</code> does not use the quoter.</p>
<p>Since <code>quoter</code> is <code>immutable</code>, a misconfigured deployment cannot be fixed and must be redeployed.</p>
<h3 id="recommendation-6">Recommendation</h3>
<p>The <code>_<wbr/>quoter</code> parameter should be added to the zero-address validation for consistency with other parameters.</p>
<h3 id="client-response-6">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-008"></a><h2 id="io-prv-aps-008-missing-authority-zero-check" class="break-before"><strong>IO-PRV-APS-008</strong> Missing authority zero-check</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol#L80-L94">Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol<wbr/>#L80-L94</a></td>
</tr>
</tbody>
</table>
<p>The <code>Prvl<wbr/>Aave<wbr/>Borrow</code> constructor validates <code>_<wbr/>owner</code>, <code>_<wbr/>uniswap<wbr/>V3Router</code>, <code>_<wbr/>aave</code>, and <code>_<wbr/>vault</code> for zero address, but does not validate <code>_<wbr/>authority</code>:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">constructor</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="kt">address</span> <span class="n">_owner</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="kt">address</span> <span class="n">_authority</span><span class="p">,</span>      <span class="c1">// NOT zero-checked
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">address</span> <span class="n">_uniswapV3Router</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="kt">address</span> <span class="n">_aave</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="kt">address</span> <span class="n">_vault</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="n">Auth</span><span class="p">(</span><span class="n">_owner</span><span class="p">,</span> <span class="n">Authority</span><span class="p">(</span><span class="n">_authority</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">_owner</span> <span class="o">==</span> <span class="kt">address</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="nb">revert</span> <span class="n">PrvlAaveBorrow__invalidZeroAddress</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">_uniswapV3Router</span> <span class="o">==</span> <span class="kt">address</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="nb">revert</span> <span class="n">PrvlAaveBorrow__invalidZeroAddress</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">_aave</span> <span class="o">==</span> <span class="kt">address</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="nb">revert</span> <span class="n">PrvlAaveBorrow__invalidZeroAddress</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">_vault</span> <span class="o">==</span> <span class="kt">address</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="nb">revert</span> <span class="n">PrvlAaveBorrow__invalidZeroAddress</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// _authority not checked
</span></span></span></code></pre><p>With <code>authority == address(0)</code>, the first condition in Solmate’s <code>is<wbr/>Authorized()</code> is always false, so only <code>user == owner</code> grants access. This means vault functions cannot be called by the vault via <code>Roles<wbr/>Authority</code>, rendering the adaptor unusable by the vault system.</p>
<h3 id="recommendation-7">Recommendation</h3>
<p>The <code>_<wbr/>authority</code> parameter should be added to the zero-address validation for consistency with other parameters.</p>
<h3 id="client-response-7">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Aave<wbr/>Borrow</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-009"></a><h2 id="io-prv-aps-009-repay-amountin-not-validated-against-supplyamount" class="break-before"><strong>IO-PRV-APS-009</strong> repay() amountIn not validated against supplyAmount</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/micro-managers/PrvlFlashloanAaveBorrowV5.sol#L156-L158">Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>sol<wbr/>#L156-L158</a></td>
</tr>
</tbody>
</table>
<p>In <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>repay()</code>, the caller provides three independent parameters: <code>borrow<wbr/>Amount</code>, <code>supply<wbr/>Amount</code>, and <code>exact<wbr/>Input<wbr/>Params</code>. The function passes these directly to <code>get<wbr/>Repay<wbr/>User<wbr/>Data()</code> without validating their coherence. The repay flow is:</p>
<ol>
<li>Repay <code>borrow<wbr/>Amount</code> of debt to Aave</li>
<li>Withdraw <code>supply<wbr/>Amount</code> of collateral (deposit token) from Aave</li>
<li>Swap the withdrawn deposit token to base token using <code>exact<wbr/>Input<wbr/>Params</code></li>
</ol>
<p>For the swap to consume all withdrawn collateral, <code>exact<wbr/>Input<wbr/>Params.<wbr/>amount<wbr/>In</code> should equal <code>supply<wbr/>Amount</code>. However, there is no validation that this is the case. Mismatched values would either cause a revert (safe failure) or leave unused tokens in the vault.</p>
<h3 id="recommendation-8">Recommendation</h3>
<p>Validation should be added to ensure <code>exact<wbr/>Input<wbr/>Params.<wbr/>amount<wbr/>In</code> equals <code>supply<wbr/>Amount</code>.</p>
<h3 id="client-response-8">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-010"></a><h2 id="io-prv-aps-010-settle-amountin-unknowable-due-to-interest-accrual" class="break-before"><strong>IO-PRV-APS-010</strong> settle() amountIn unknowable due to interest accrual</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/micro-managers/PrvlFlashloanAaveBorrowV5.sol#L162-L166">Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>sol<wbr/>#L162-L166</a></td>
</tr>
</tbody>
</table>
<p>In <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>settle()</code>, the function withdraws all collateral using <code>type(uint256).<wbr/>max</code> but requires the caller to provide <code>exact<wbr/>Input<wbr/>Params.<wbr/>amount<wbr/>In</code> for the subsequent swap:</p>
<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">function</span> <span class="nf">settle</span><span class="p">(</span><span class="n">DecoderCustomTypes</span><span class="p">.</span><span class="n">ExactInputParamsRouter02</span> <span class="n">calldata</span> <span class="n">exactInputParams</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">external</span> <span class="n">requiresAuth</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint256</span> <span class="n">debtAmount</span> <span class="o">=</span> <span class="n">ERC20</span><span class="p">(</span><span class="n">debtToken</span><span class="p">).</span><span class="n">balanceOf</span><span class="p">(</span><span class="n">boringVault</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bytes</span> <span class="k">memory</span> <span class="n">innerUserData</span> <span class="o">=</span> <span class="n">getRepayUserData</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="nb">type</span><span class="p">(</span><span class="nc">uint256</span><span class="p">).</span><span class="nb">max</span><span class="p">,</span> <span class="nb">type</span><span class="p">(</span><span class="nc">uint256</span><span class="p">).</span><span class="nb">max</span><span class="p">,</span> <span class="n">exactInputParams</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">_executeFlashloan</span><span class="p">(</span><span class="n">innerUserData</span><span class="p">,</span> <span class="n">debtAmount</span><span class="p">.</span><span class="n">mulDivDown</span><span class="p">(</span><span class="mi">105</span><span class="p">,</span> <span class="mi">100</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre><p>The actual collateral amount withdrawn depends on the aToken balance at execution time, which accrues interest block by block. The caller must provide <code>amount<wbr/>In</code> before knowing the exact withdrawal amount.</p>
<p>If <code>amount<wbr/>In</code> is less than the actual withdrawn amount, some deposit token remains unused in the vault after the swap. If <code>amount<wbr/>In</code> is greater than the actual withdrawn amount, the swap reverts.</p>
<h3 id="recommendation-9">Recommendation</h3>
<p>It should be documented that <code>settle()</code> may leave dust and require a follow-up sweep operation. Alternatively, the aToken balance should be read and validated against the provided <code>amount<wbr/>In</code>.</p>
<h3 id="client-response-9">Client response</h3>
<p>Closed due to the removal of the legacy file <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</p>
<a name="IO-PRV-APS-011"></a><h2 id="io-prv-aps-011-foundry-key-management" class="break-before"><strong>IO-PRV-APS-011</strong> Foundry key management</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-open">Open</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/tree/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions">script/Permissions/</a></td>
</tr>
</tbody>
</table>
<p>The permission scripts load private keys from a <code>.<wbr/>env</code> file to sign messages as the Paravel deployer. This approach requires the private key to be exported from the wallet and stored in plain text on the host machine. If the host were compromised, an attacker would have direct access to the key.</p>
<h3 id="recommendation-10">Recommendation</h3>
<p>Foundry’s <a href="https://getfoundry.sh/guides/best-practices/key-management/">key management best practices</a> support hardware wallets for signing messages. This approach is more robust, as the private key is not exported from the hardware device; instead, Foundry constructs the message, sends it to the wallet for signing, and receives the signed output.</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>ID</th>
<th>Location</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>IO-PRV-APS-012</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/micro-managers/PrvlFlashloanAaveBorrowV5.sol#L38">Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>sol<wbr/>#L38</a></td>
<td><code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> defines <code>MAX_<wbr/>SLIPPAGE = 0.<wbr/>1e4</code>, which is never referenced anywhere in the contract. This creates the misleading impression that slippage is bounded. The unused constant should be removed or actual slippage validation should be implemented.</td>
</tr>
<tr>
<td>IO-PRV-APS-013</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/micro-managers/PrvlFlashloanAaveBorrowV5.sol#L77">Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5.<wbr/>sol<wbr/>#L77</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol#L206">Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol<wbr/>#L206</a></td>
<td>When setting the <code>aave<wbr/>Variable<wbr/>Rate</code> in the <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> constructor and <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>set<wbr/>Token<wbr/>Config()</code>, the value should be confirmed to be <code>2</code> for variable rates. Other values are <a href="https://aave.com/docs/aave-v3/smart-contracts/pool#write-methods-borrow-input-parameters">invalid</a> for Paravel vaults.</td>
</tr>
<tr>
<td>IO-PRV-APS-014</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/src/adaptors/PrvlAaveBorrow.sol#L241-L243">Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sol<wbr/>#L241-L243</a></td>
<td>The <code>Prvl<wbr/>Aave<wbr/>Borrow.<wbr/>sweep<wbr/>ERC20()</code> function transfers tokens to the vault but does not emit an event. All other state-changing functions emit events, making this an inconsistency. A <code>Tokens<wbr/>Swept</code> event should be added.</td>
</tr>
<tr>
<td>IO-PRV-APS-015</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/AddAgentTeamPermmisons.s.sol">Add<wbr/>Agent<wbr/>Team<wbr/>Permmisons.<wbr/>s.<wbr/>sol</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/SetPrvlPermisionsMainnetUSDC.s.sol#L47">Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>USDC.<wbr/>s.<wbr/>sol<wbr/>#L47</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/SetPrvlPermisionsMainnetWETH.s.sol#L46">Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>WETH.<wbr/>s.<wbr/>sol<wbr/>#L46</a></td>
<td>Several file names contain typos (e.g. “Permmisons” → “Permissions”, “Permisions” → “Permissions”). Additionally, “custome” should be “custom” in <code>Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>USDC.<wbr/>s.<wbr/>sol</code> (L47) and <code>Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>WETH.<wbr/>s.<wbr/>sol</code> (L46).</td>
</tr>
<tr>
<td>IO-PRV-APS-016</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/tree/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions">script/Permissions/</a></td>
<td>All deployed contract addresses and role constants are declared independently within each script, with no shared constants file. This design has poor readability and is likely to cause copy-paste errors. A shared constants contract should be created and inherited by all scripts.</td>
</tr>
<tr>
<td>IO-PRV-APS-017</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/tree/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions">script/Permissions/</a></td>
<td>Scripts could be organised into subdirectories based on the target chain (e.g., <code>mainnet/</code>, <code>sepolia/</code>, <code>local/</code>). If scripts are intended to be executed in a specific order, a number could be appended to indicate sequence, or the sequence could be consolidated into a monolithic script.</td>
</tr>
<tr>
<td>IO-PRV-APS-018</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/SetPrvlPermisionsMainnetUSDC.s.sol">Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>USDC.<wbr/>s.<wbr/>sol</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/SetPrvlPermisionsMainnetWETH.s.sol">Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>WETH.<wbr/>s.<wbr/>sol</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/SetPrvlAgentPermisionsMainnetForkUSDC.s.sol">Set<wbr/>Prvl<wbr/>Agent<wbr/>Permisions<wbr/>Mainnet<wbr/>Fork<wbr/>USDC.<wbr/>s.<wbr/>sol</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/SetPrvlAgentPermisionsSepoliaUSDC.s.sol">Set<wbr/>Prvl<wbr/>Agent<wbr/>Permisions<wbr/>Sepolia<wbr/>USDC.<wbr/>s.<wbr/>sol</a></td>
<td>Variables already typed as <code>address</code> are unnecessarily wrapped in <code>address()</code> when passed to <code>set<wbr/>User<wbr/>Role()</code> in <code>Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>USDC.<wbr/>s.<wbr/>sol</code>, <code>Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>WETH.<wbr/>s.<wbr/>sol</code>, <code>Set<wbr/>Prvl<wbr/>Agent<wbr/>Permisions<wbr/>Mainnet<wbr/>Fork<wbr/>USDC.<wbr/>s.<wbr/>sol</code>, and <code>Set<wbr/>Prvl<wbr/>Agent<wbr/>Permisions<wbr/>Sepolia<wbr/>USDC.<wbr/>s.<wbr/>sol</code>. The redundant casts should be removed.</td>
</tr>
<tr>
<td>IO-PRV-APS-019</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/TransferAuths.s.sol">Transfer<wbr/>Auths.<wbr/>s.<wbr/>sol</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/SetPrvlPermisionsMainnetUSDC.s.sol">Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>USDC.<wbr/>s.<wbr/>sol</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/RemoveTestAddress.s.sol">Remove<wbr/>Test<wbr/>Address.<wbr/>s.<wbr/>sol</a></td>
<td>Several scripts contain unused variables and imports: <code>Transfer<wbr/>Auths.<wbr/>s.<wbr/>sol</code> has an unused <code>test<wbr/>Address</code> variable; <code>Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>USDC.<wbr/>s.<wbr/>sol</code> has an unused <code>Boring<wbr/>Solver</code> import; <code>Remove<wbr/>Test<wbr/>Address.<wbr/>s.<wbr/>sol</code> has an unused <code>updated<wbr/>User<wbr/>Roles</code> variable (missing verification check); and multiple files contain unused <code>Authority</code> and <code>Std<wbr/>Json</code> imports.</td>
</tr>
<tr>
<td>IO-PRV-APS-020</td>
<td><a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/GrantStrategistMultisigRole.s.sol">Grant<wbr/>Strategist<wbr/>Multisig<wbr/>Role.<wbr/>s.<wbr/>sol</a>, <a href="https://github.com/ParavelDAO/boring-vault/blob/b5154a8f2978681b7d3f25fda16e2d3cef4f3f6d/script/Permissions/GrantAgentAuthorityRole.s.sol">Grant<wbr/>Agent<wbr/>Authority<wbr/>Role.<wbr/>s.<wbr/>sol</a></td>
<td><code>Grant<wbr/>Strategist<wbr/>Multisig<wbr/>Role.<wbr/>s.<wbr/>sol</code> and <code>Grant<wbr/>Agent<wbr/>Authority<wbr/>Role.<wbr/>s.<wbr/>sol</code> have network selection logic in <code>set<wbr/>Up()</code> but <code>run()</code> uses hardcoded addresses that ignore the selection. A helper function <code>get<wbr/>Roles<wbr/>Authority<wbr/>Address()</code> exists but is never called. The helper function should be used in <code>run()</code>, or the network selection logic should be removed entirely.</td>
</tr>
</tbody>
</table>
<h3 id="client-response-10">Client response</h3>
<dl>
<dt>IO-PRV-APS-012</dt>
<dd>Closed due to the removal of the legacy file <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</dd>
<dt>IO-PRV-APS-013</dt>
<dd>Closed due to the removal of the legacy files <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code>, and <code>Prvl<wbr/>Aave<wbr/>Borrow</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</dd>
<dt>IO-PRV-APS-014</dt>
<dd>Closed due to the removal of the legacy file <code>Prvl<wbr/>Aave<wbr/>Borrow</code> in <a href="https://github.com/ParavelDAO/prvl-protocol/commit/56629206dd336503416822c91e87d4fac4e9ec90"><code>5662920</code></a>.</dd>
<dt>IO-PRV-APS-015</dt>
<dd>Open.</dd>
<dt>IO-PRV-APS-016</dt>
<dd>Open.</dd>
<dt>IO-PRV-APS-017</dt>
<dd>Open.</dd>
<dt>IO-PRV-APS-018</dt>
<dd>Open.</dd>
<dt>IO-PRV-APS-019</dt>
<dd>Open.</dd>
<dt>IO-PRV-APS-020</dt>
<dd>Open.</dd>
</dl>
<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="system-architecture">System architecture</h2>
<p>The Paravel protocol uses a two-tier vault architecture built on the Boring Vault framework. End users deposit into client vaults (e.g., iPrvlWETH, iPrvlUSDC), which allocate capital to agent vaults via cross-vault transfers. Agent vaults execute DeFi strategies – primarily leveraged Aave V3 lending positions with Uniswap V3 swaps.</p>
<p>All vault operations are gated by Solmate’s <code>Auth</code> and <code>Roles<wbr/>Authority</code>. Each vault instance has its own <code>Roles<wbr/>Authority</code> contract. The <code>Manager<wbr/>With<wbr/>Merkle<wbr/>Verification</code> contract restricts vault operations via merkle proofs, where each leaf encodes a decoder/sanitizer address, a target contract, whether ETH can be sent, a function selector, and packed address arguments.</p>
<h2 id="prvlaaveborrow">PrvlAaveBorrow</h2>
<p><code>Prvl<wbr/>Aave<wbr/>Borrow</code> was a standalone adaptor contract that handled Aave V3 supply/borrow leverage positions with Uniswap V3 swaps. It inherited Solmate’s <code>Auth</code> for access control and <code>Reentrancy<wbr/>Guard</code>.</p>
<p>The call flow was: Strategist → <code>Manager<wbr/>With<wbr/>Merkle<wbr/>Verification</code> → <code>Boring<wbr/>Vault.<wbr/>manage()</code> → <code>Prvl<wbr/>Aave<wbr/>Borrow</code>.</p>
<p>The adaptor supported multiple token pairs via a <code>token<wbr/>Configs</code> mapping. Each <code>Token<wbr/>Config</code> stored the base token (borrowed asset, e.g., WETH), deposit token (collateral, e.g., wstETH), Aave aToken/debtToken addresses, interest rate mode, and Uniswap V3 swap paths. The config ID was a deterministic hash of the four token addresses.</p>
<p>The three core functions were:</p>
<dl>
<dt><code>supply()</code></dt>
<dd>Opened or increased a leveraged position. Pulled base token from the vault, swapped to deposit token via Uniswap V3, supplied to Aave as collateral on behalf of the vault, borrowed base token from Aave on behalf of the vault, and returned borrowed tokens to the vault.</dd>
<dt><code>reduce<wbr/>Position()</code></dt>
<dd>Partially unwound a position. Pulled base token, repaid Aave debt, pulled aTokens, withdrew collateral from Aave, swapped deposit token back to base token and returned it to the vault.</dd>
<dt><code>settle()</code></dt>
<dd>Fully closed a position. Dynamically read the vault’s current debt and collateral balances, repaid all debt, withdrew all collateral, and swapped everything back to base token.</dd>
</dl>
<p>Admin functions (<code>set<wbr/>Token<wbr/>Config</code>, <code>remove<wbr/>Token<wbr/>Config</code>, <code>sweep<wbr/>ERC20</code>) managed the token configuration registry and handled emergency token recovery.</p>
<p>The adaptor transiently held tokens during operations – all tokens started and ended in the <code>Boring<wbr/>Vault</code>. The vault must have pre-approved the adaptor for base token and aToken transfers, and must have called <code>approve<wbr/>Delegation()</code> on the Aave debt token to allow the adaptor to borrow on its behalf.</p>
<h2 id="prvlflashloanaaveborrowv5">PrvlFlashloanAaveBorrowV5</h2>
<p><code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> extended <code>UManager</code> and used Balancer flash loans to execute the full leverage loop atomically. Unlike <code>Prvl<wbr/>Aave<wbr/>Borrow</code>, this contract stored merkle proofs on-chain via six setter functions and supported a single token pair per deployment (all token addresses were immutable).</p>
<p>The call flow involved two-level merkle verification: an <strong>outer proof</strong> authorized the vault to call <code>Manager.<wbr/>flash<wbr/>Loan()</code>, and <strong>inner proofs</strong> authorized the actual DeFi operations (swap, supply, borrow or repay, withdraw) that executed inside the flashloan callback.</p>
<p>The three core functions (<code>borrow</code>, <code>repay</code>, <code>settle</code>) each constructed nested calldata and executed it via <code>_<wbr/>execute<wbr/>Flashloan()</code>, which in turn called <code>manager.<wbr/>manage<wbr/>Vault<wbr/>With<wbr/>Merkle<wbr/>Verification()</code>.</p>
<p>Both <code>Prvl<wbr/>Aave<wbr/>Borrow</code> and <code>Prvl<wbr/>Flashloan<wbr/>Aave<wbr/>Borrow<wbr/>V5</code> were removed during the audit. In the current production architecture, borrow, repay, and settle operations are composed off-chain and submitted directly to the vault via <code>manage<wbr/>Vault<wbr/>With<wbr/>Merkle<wbr/>Verification</code> on <code>Manager<wbr/>With<wbr/>Merkle<wbr/>Verification.<wbr/>sol</code>. The merkle root, which is maintained by the team multisig / Vault System Owner, governs which operations are permitted. No on-chain adaptor currently fulfils this role.</p>
<h2 id="permission-scripts">Permission scripts</h2>
<p>Twelve Foundry scripts in <code>script/Permissions/</code> configure the protocol’s role-based access control system. These scripts grant roles such as <code>OWNER_<wbr/>ROLE</code>, <code>UPDATE_<wbr/>EXCHANGE_<wbr/>RATE_<wbr/>ROLE</code>, and <code>DEPOSITOR_<wbr/>VAULT_<wbr/>ROLE</code> primarily to Gnosis Safe multisig addresses and set role capabilities on target contracts. The mainnet permission scripts (<code>Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>USDC.<wbr/>s.<wbr/>sol</code>, <code>Set<wbr/>Prvl<wbr/>Permisions<wbr/>Mainnet<wbr/>WETH.<wbr/>s.<wbr/>sol</code>) are the primary production scripts, while others handle testnet deployments, role grants, and administrative operations.</p>

</article>
</main>
</div>

Secure your system.
Request a service
Start Now