Wormhole Solidity SDK Smart Contract Audit

<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: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}.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 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>
<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">Solidity SDK Smart Contract Audit</div>
<div class="frontpage-subtitle">Wormhole, 8 January 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-wrm-sdk-001-incorrect-offset-used">IO-WRM-SDK-001 Incorrect offset used</a></li>
<li>
<a href="#io-wrm-sdk-002-rename-return-variable">IO-WRM-SDK-002 Rename return variable</a></li>
<li>
<a href="#io-wrm-sdk-003-unnecessary-cast">IO-WRM-SDK-003 Unnecessary cast</a></li>
<li>
<a href="#io-wrm-sdk-004-missing-warnings-for-keccak-functions">IO-WRM-SDK-004 Missing warnings for Keccak functions</a></li>
<li>
<a href="#io-wrm-sdk-005-unused-constants">IO-WRM-SDK-005 Unused Constants</a></li>
<li>
<a href="#io-wrm-sdk-006-sequence-based-replay-protection-griefing">IO-WRM-SDK-006 Sequence-based replay protection griefing</a></li>
<li>
<a href="#io-wrm-sdk-007-recalculate-envelope-size">IO-WRM-SDK-007 Recalculate envelope size</a></li>
<li>
<a href="#io-wrm-sdk-008-free-memory-space-access-assumptions">IO-WRM-SDK-008 Free memory space access assumptions</a></li>
</ul>
</li>
<li>
<a href="#specification">Specification</a><ul>
<li>
<a href="#bytesparsing">BytesParsing</a></li>
<li>
<a href="#vaalib">VaaLib</a></li>
<li>
<a href="#replayprotection">ReplayProtection</a></li>
<li>
<a href="#proxy-contracts">Proxy contracts</a></li>
<li>
<a href="#keccak-utilities">Keccak utilities</a></li>
<li>
<a href="#permitparsing">PermitParsing</a></li>
<li>
<a href="#percentage">Percentage</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 Wormhole to perform a smart contract audit of their Solidity SDK library. Two auditors conducted the audit between 09 December 2025 and 06 January 2026, over 11 audit days.</p>
<h4 id="overview">Overview</h4>
<p>The assessment focused on several core library and utility components intended to be consumed by other projects. Integrators should exercise caution when consuming these components and ensure that the security and functional considerations documented in the comments (particularly around unchecked parsing and hashing helpers) are strictly adhered to.</p>
<p>The audit identified one critical issue and seven informational findings. All issues were either resolved through code changes or closed as acceptable design trade-offs, and there were no open findings at the conclusion of the engagement.</p>
<p>Most findings were related to design and robustness concerns rather than exploitable vulnerabilities that would directly put funds at risk. With these considerations addressed, the reviewed library components are well-positioned for safe integration, provided that the documented usage constraints are respected by downstream consumers.</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>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>4</td>
</tr>
<tr>
<td>Closed</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>3</td>
</tr>
</tbody>
</table>
<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/wormhole-foundation/wormhole-solidity-sdk/tree/main">wormhole-solidity-sdk</a></li>
<li><strong>Initial audit commit:</strong> <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd">97ca219</a></li>
<li><strong>Final review commit:</strong> <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/b4a904ec8c807f9d01c5eacfb975c89dc40012a3">b4a904e</a></li>
<li><strong>Files:</strong>
<ul>
<li><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/BytesParsing.sol">src/libraries/BytesParsing.sol</a></li>
<li><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/VaaLib.sol">src/libraries/VaaLib.sol</a></li>
<li><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/ReplayProtection.sol">src/libraries/ReplayProtection.sol</a></li>
<li><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/tree/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/proxy">src/proxy</a></li>
<li><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/utils/Keccak.sol">src/utils/Keccak.sol</a></li>
<li><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/PermitParsing.sol">src/libraries/PermitParsing.sol</a></li>
<li><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/Percentage.sol">src/libraries/Percentage.sol</a></li>
</ul>
</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 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, 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-WRM-SDK-001">IO-WRM-SDK-001</a></td>
<td>Incorrect offset used</td>
<td class="rating-critical">Critical</td>
<td class="status-resolved">Resolved</td>
</tr>
<tr>
<td><a href="#IO-WRM-SDK-002">IO-WRM-SDK-002</a></td>
<td>Rename return variable</td>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
</tr>
<tr>
<td><a href="#IO-WRM-SDK-003">IO-WRM-SDK-003</a></td>
<td>Unnecessary cast</td>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
</tr>
<tr>
<td><a href="#IO-WRM-SDK-004">IO-WRM-SDK-004</a></td>
<td>Missing warnings for Keccak functions</td>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
</tr>
<tr>
<td><a href="#IO-WRM-SDK-005">IO-WRM-SDK-005</a></td>
<td>Unused Constants</td>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
</tr>
<tr>
<td><a href="#IO-WRM-SDK-006">IO-WRM-SDK-006</a></td>
<td>Sequence-based replay protection griefing</td>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-WRM-SDK-007">IO-WRM-SDK-007</a></td>
<td>Recalculate envelope size</td>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
</tr>
<tr>
<td><a href="#IO-WRM-SDK-008">IO-WRM-SDK-008</a></td>
<td>Free memory space access assumptions</td>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</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-WRM-SDK-001"></a><h2 id="io-wrm-sdk-001-incorrect-offset-used" class="break-before"><strong>IO-WRM-SDK-001</strong> Incorrect offset used</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-critical">Critical</td>
<td class="status-resolved">Resolved</td>
<td><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/VaaLib.sol#L430">VaaLib.sol#L430</a></td>
</tr>
</tbody>
</table>
<p>In <code>VaaLib::decodeVaaBodyStructMem()</code>, an offset of 0 was passed to <code>VaaLib::decodeVaaBodyMemUnchecked()</code>. This was incorrect because the decode function expects an offset at the end of the header and beginning of the envelope. Given an offset of 0, the function attempts to decode the envelope from within the header, producing incorrect data.</p>
<h3 id="recommendation">Recommendation</h3>
<p>The correct approach, as used in other functions, is to calculate the offset that skips the header by calling <code>VaaLib::skipVaaHeaderMemUnchecked(encodedVaa, 0)</code> and pass that offset to <code>VaaLib::decodeVaaBodyMemUnchecked()</code>.</p>
<h3 id="client-response">Client response</h3>
<p>This issue was resolved in <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/pull/113/commits/109135d7370151008a0935588aaf2c1aa8ff9848">109135d</a>, where <code>VaaLib::decodeVaaBodyStructMem()</code> was updated to call <code>VaaLib::decodeVaaBodyMem()</code>, which handles the offset calculation correctly.</p>
<a name="IO-WRM-SDK-002"></a><h2 id="io-wrm-sdk-002-rename-return-variable" class="break-before"><strong>IO-WRM-SDK-002</strong> Rename return variable</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
<td><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/VaaLib.sol#L1089">VaaLib.sol#L1089</a></td>
</tr>
</tbody>
</table>
<p>The returned offset from <code>VaaLib::decodeGuardianSignatureMemUnchecked()</code> should be renamed from <code>envelopeOffset</code> to <code>newOffset</code>, similar to <code>VaaLib::decodeGuardianSignatureCdUnchecked()</code>. This is because this function will likely be called in a loop, meaning only the last call would actually be the <code>envelopeOffset</code>.</p>
<h3 id="client-response-1">Client response</h3>
<p>The return variable was renamed in <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/pull/113/commits/109135d7370151008a0935588aaf2c1aa8ff9848">109135d</a>.</p>
<a name="IO-WRM-SDK-003"></a><h2 id="io-wrm-sdk-003-unnecessary-cast" class="break-before"><strong>IO-WRM-SDK-003</strong> Unnecessary cast</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
<td><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/BytesParsing.sol#L381-L384">BytesParsing.sol#L381-L384</a></td>
</tr>
</tbody>
</table>
<p>A cast from <code>uint8</code> to <code>uint256</code> was used in <code>BytesParsing::asBoolCdUnchecked()</code>. This may be unnecessary as booleans are equivalent to <code>uint8</code>. As such, the final <code>val</code> value could be assigned to <code>ret</code> directly.</p>
<h3 id="client-response-2">Client response</h3>
<p>The cast was used to clear the upper 31 bytes. However, an improvement was implemented in <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/pull/113/commits/abf970684cde19650fbf4f3d3f71ac015ce432c3">abf9706</a> to reorder the cleaning step to avoid two extra 0xff masking operations.</p>
<a name="IO-WRM-SDK-004"></a><h2 id="io-wrm-sdk-004-missing-warnings-for-keccak-functions" class="break-before"><strong>IO-WRM-SDK-004</strong> Missing warnings for Keccak functions</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-resolved">Resolved</td>
<td><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/utils/Keccak.sol#L14">Keccak.sol#L14</a></td>
</tr>
</tbody>
</table>
<p>A warning explaining the risks of unchecked functions, similar to the format at the top of the <code>BytesParsing.sol</code> library, was not present for the Keccak free functions. This was especially true for the <code>Keccak::keccak256SliceUnchecked()</code> function since an invalid <code>offset</code> or <code>length</code> value would hash invalid data, creating an invalid hash.</p>
<h3 id="client-response-3">Client response</h3>
<p>A comment with the necessary warnings was added above the function in <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/pull/113/commits/57ad49bf459a423b7a01dcae90a9fea96d8b3fb6">57ad49b</a>.</p>
<a name="IO-WRM-SDK-005"></a><h2 id="io-wrm-sdk-005-unused-constants" class="break-before"><strong>IO-WRM-SDK-005</strong> Unused 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/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/VaaLib.sol#L249">VaaLib.sol#L249</a>, <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/VaaLib.sol#L263">VaaLib.sol#L263</a>, <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/VaaLib.sol#L286">VaaLib.sol#L286</a>, <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/Percentage.sol#L26">Percentage.sol#L26</a>, <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/Percentage.sol#L29">Percentage.sol#L29</a></td>
</tr>
</tbody>
</table>
<p>The following constants were unused in <code>VaaLib.sol</code>. These could be removed unless the intention is to allow contracts that derive from this library access to these constants:</p>
<ul>
<li><code>MULTISIG_SIGNATURE_ARRAY_OFFSET</code></li>
<li><code>MULTISIG_SIGNATURE_V_OFFSET</code></li>
<li><code>SCHNORR_ENVELOPE_OFFSET</code></li>
</ul>
<p>Similarly, the following constants were unused in <code>Percentage.sol</code>.</p>
<ul>
<li><code>BYTE_SIZE</code></li>
<li><code>EXPONENT_BASE</code></li>
</ul>
<h3 id="client-response-4">Client response</h3>
<p><code>EXPONENT_BASE</code>, which had no utility, was removed in <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/pull/113/commits/0fd4257562122410adb251fba8eb9b4d0bd5447e">0fd4257</a>. The rest of the constants were kept for reference for consuming contracts.</p>
<a name="IO-WRM-SDK-006"></a><h2 id="io-wrm-sdk-006-sequence-based-replay-protection-griefing" class="break-before"><strong>IO-WRM-SDK-006</strong> Sequence-based replay protection griefing</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/ReplayProtection.sol#L65">ReplayProtection.sol#L65</a></td>
</tr>
</tbody>
</table>
<p>When determining the base slot for a given emitter address and chain, the values are XORed instead of encoded and packed. Due to XOR involution, an attacker could attempt to derive an emitter address that satisfies <code>attacker_emitter == target_emitter XOR target_chain_id XOR attacker_chain_id</code>. This would allow them to access the same base slot and set the replay protection flags for sequence numbers not yet reached by the valid emitter.</p>
<p>While theoretically possible, it would require the attacker to be able to deploy an emitter at a specific address on their attack chain. Currently, it is infeasible to do this on existing chains.</p>
<p>A more robust approach would be to derive the base slot using <code>abi.encodePacked</code> instead of using XOR.</p>
<h3 id="client-response-5">Client response</h3>
<p>The team acknowledged this as a theoretical design consideration and opted to leave the implementation unchanged.</p>
<a name="IO-WRM-SDK-007"></a><h2 id="io-wrm-sdk-007-recalculate-envelope-size" class="break-before"><strong>IO-WRM-SDK-007</strong> Recalculate envelope size</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/VaaLib.sol#L312-L313">VaaLib.sol#L312-L313</a></td>
</tr>
</tbody>
</table>
<p><code>ENVELOPE_SIZE</code> could be calculated based on the sum of its individual element sizes. While the current calculation is correct, it is based on an assumption that the <code>ENVELOPE_TIMESTAMP_OFFSET</code> will always be zero. Should this change in a future refactor, the <code>ENVELOPE_SIZE</code> may become incorrect, and this could be missed in that refactor. Furthermore, calculating it based on the sum of element sizes aligns with the convention used in calculating other <code>*_SIZE</code> constants in the library, such as <code>MULTISIG_GUARDIAN_SIGNATURE_SIZE</code>.</p>
<h3 id="client-response-6">Client response</h3>
<p>The team acknowledged this as a maintainability consideration and opted to leave the implementation unchanged.</p>
<a name="IO-WRM-SDK-008"></a><h2 id="io-wrm-sdk-008-free-memory-space-access-assumptions" class="break-before"><strong>IO-WRM-SDK-008</strong> Free memory space access assumptions</h2>
<table class="metadata">

<tbody>
<tr>
<td class="rating-informational">Informational</td>
<td class="status-closed">Closed</td>
<td><a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/libraries/BytesParsing.sol#L82">BytesParsing.sol#L82</a>, <a href="https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/97ca219eb34af71b80678cbf7bb10ff0cbb0f5bd/src/utils/Keccak.sol#L32">Keccak.sol#L32</a></td>
</tr>
</tbody>
</table>
<p>Multiple functions in the SDK access free memory space directly without moving the pointer beyond the data or clearing the data. Hence, for any operations that use this memory space, the data cannot be assumed to be padded with zeros. The offset and size values used should match the data exactly to avoid padding with junk data.</p>
<p>In a similar vein, any data calculated in the free memory space should be returned to the call stack for use and not accessed through the free memory space to prevent corruption.</p>
<h3 id="client-response-7">Client response</h3>
<p>The team acknowledged this as an integration consideration and opted to leave the implementation unchanged.</p>
<h1 id="specification">Specification</h1>
<p>The following section outlines the SDK’s intended functionality at a high level, based on its implementation in the codebase. The assessed components are library and utility building blocks intended to be consumed by other projects. They prioritize gas efficiency (including the use of inline assembly where appropriate), which places additional responsibility on downstream integrators to satisfy the documented preconditions, such as providing correct offsets and lengths to unchecked parsing and hashing helpers.</p>
<h2 id="bytesparsing">BytesParsing</h2>
<p><code>BytesParsing.sol</code> provides the SDK’s low-level byte decoding primitives and serves as the foundation for the higher-level parsing libraries. The implementation prioritizes gas efficiency, using inline assembly where appropriate, and exposes distinct variants for both calldata and memory inputs.</p>
<p>In general, functions are offered in four forms: calldata (<code>Cd</code>) and memory (<code>Mem</code>) variants, each with a bounds-checked version and an <code>Unchecked</code> version. The checked variants protect only against out-of-bounds reads of the provided buffer; they do not protect against arithmetic overflow when computing offsets and lengths.</p>
<p>The intended high-efficiency integration pattern is to parse from calldata where possible and, when using unchecked helpers, to validate correctness at the end by performing a single full-consumption check (e.g., via <code>checkLength</code>) so the decoder consumes the payload exactly. Downstream consumers remain responsible for ensuring offsets and lengths are sensibly bounded, including validating user-controlled inputs, and for preferring encoding formats that constrain attacker-controlled length fields.</p>
<h2 id="vaalib">VaaLib</h2>
<p><code>VaaLib.sol</code> provides gas-efficient VAA parsing utilities built on top of <code>BytesParsing</code>. The library is designed to decode VAAs with minimal overhead and, where possible, to return decoded components directly on the stack rather than requiring memory allocation for a full struct.</p>
<p><code>VaaLib</code> exposes whole-VAA helpers for use cases such as skipping headers and decoding envelopes/bodies, as well as functions that parse individual VAA components and advance offsets to support iterative decoding, for use cases such as decoding guardian signatures in a loop.</p>
<h3 id="function-variants-and-naming-conventions">Function variants and naming conventions</h3>
<dl>
<dt>Data location variants</dt>
<dd>functions are generally provided in calldata (<code>Cd</code>) and memory (<code>Mem</code>) forms.</dd>
<dt>Struct-return variants</dt>
<dd>many decoders have a “struct flavor” that returns the decoded values in an associated in-memory struct, in addition to the stack-returning variants.</dd>
<dt>Parameter naming</dt>
<dd><code>encodedVaa</code> and <code>encodedAttestation</code> are used when the input is expected to contain a single full VAA/attestation; <code>encoded</code> is used for partial inputs or buffers containing multiple items.</dd>
<dt>Unchecked suffix</dt>
<dd><code>Unchecked</code> denotes the absence of bounds checks - it is not Solidity’s <code>unchecked</code> keyword. Arithmetic is performed using unchecked operations as overflows are not expected under the VAA format’s constraints, while underflow conditions are explicitly checked where relevant.</dd>
<dt><code>Vaa</code> tag in function names</dt>
<dd>function names include <code>Vaa</code> to improve clarity and reduce the risk of name collisions when used with <code>using ... for bytes</code>.</dd>
</dl>
<h2 id="replayprotection">ReplayProtection</h2>
<p><code>ReplayProtection.sol</code> provides reusable replay protection primitives intended to prevent a VAA (or message) from being processed more than once. Two replay protection approaches are supported:</p>
<ul>
<li>
<p>Sequence-based replay protection (per chain + emitter)</p>
<ul>
<li>Tracks replay status per <code>(emitterChainId, emitterAddress)</code> using the VAA sequence number.</li>
<li>Must only be used for VAAs published with the finalized consistency level (the default case).</li>
<li>Implemented via a bitmap to reduce gas cost by avoiding writes to clean storage slots wherever possible.</li>
</ul>
</li>
<li>
<p>Hash-based replay protection</p>
<ul>
<li>Can be used for all consistency levels.</li>
<li>Less efficient than sequence-based replay protection because it always writes to a clean storage slot.</li>
<li>Uses the canonical VAA hash. Note that this is not what CoreBridge returns in <code>VM.hash</code> – see the warning box at the top of <code>VaaLib.sol</code> for details.</li>
</ul>
</li>
</ul>
<h2 id="proxy-contracts">Proxy contracts</h2>
<p>The <code>src/proxy</code> components provide a slimmed-down, opinionated implementation of the EIP-1967 proxy pattern (based on the reference implementation) intended for downstream consumers that require upgradeability or call forwarding.</p>
<p>Provision is included for consumers to upgrade from an OpenZeppelin proxy implementation. However, care must be taken during such a migration to ensure that the EIP-1967 proxy admin and implementation storage locations are migrated correctly, as incorrect slot handling can lead to loss of upgrade control or unexpected behavior.</p>
<h2 id="keccak-utilities">Keccak utilities</h2>
<p><code>Keccak.sol</code> provides keccak256 helper functions, including slice-based hashing utilities intended to reduce overhead when hashing sub-regions of an encoded payload. These helpers are designed for performance and include unchecked variants; callers must ensure the <code>offset</code> and <code>length</code> parameters exactly match the intended data region.</p>
<h2 id="permitparsing">PermitParsing</h2>
<p><code>PermitParsing.sol</code> standardizes the encoding and decoding of permit payloads so that consuming contracts can acquire tokens via one of the supported permit mechanisms. It supports:</p>
<ul>
<li>ERC-2612 permit (<code>IERC20Permit.permit</code>)</li>
<li>Uniswap Permit2 “permit” (approval) (<code>IAllowanceTransfer.permit</code>)</li>
<li>Uniswap Permit2 “transfer” (<code>ISignatureTransfer.permitTransferFrom</code>)</li>
</ul>
<p>The library defines a consistent on-wire format for each mechanism:</p>
<ul>
<li><strong>ERC-2612 Permit</strong>: <code>value</code> (uint256), <code>deadline</code> (uint256), <code>r</code> (bytes32), <code>s</code> (bytes32), <code>v</code> (uint8)</li>
<li><strong>Permit2 Permit</strong>: <code>amount</code> (uint160), <code>expiration</code> (uint48), <code>nonce</code> (uint48), <code>sigDeadline</code> (uint256), <code>signature</code> (bytes; 65-byte packed r,s,v)</li>
<li><strong>Permit2 Transfer</strong>: <code>amount</code> (uint256), <code>nonce</code> (uint256), <code>sigDeadline</code> (uint256), <code>signature</code> (bytes; 65-byte packed r,s,v)</li>
</ul>
<p>Decode functions are provided in 2×2 flavors: calldata (<code>Cd</code>) and memory (<code>Mem</code>) inputs, each returning either individual stack values or an associated in-memory struct (<code>Struct</code>). As with <code>BytesParsing</code>, an <code>Unchecked</code> suffix indicates that bounds checks are omitted and unchecked offset arithmetic is used.</p>
<p>The primary decode entry points are <code>decodePermit</code>, <code>decodePermit2Permit</code>, and <code>decodePermit2Transfer</code>. Encoding helpers (<code>encode*</code>) exist primarily to support testing.</p>
<h2 id="percentage">Percentage</h2>
<p><code>Percentage.sol</code> provides a compact representation of percentages using a <code>uint16</code> encoding intended to reduce storage and calldata overhead in consuming projects.</p>
<p>Percentages are represented with up to four decimal digits of precision, or up to a maximum of 1000%. The encoding uses a 14-bit mantissa and a 2-bit decimal exponent:</p>
<p>The <code>uint16</code> value is split into:</p>
<ul>
<li>a 14-bit <strong>mantissa</strong> (m) (the significant digits), and</li>
<li>a 2-bit <strong>decimal exponent</strong> (e) (a base-10 scale factor).</li>
</ul>
<p>The represented percentage is:</p>
<p><span class="math display">\[value(\%) = \frac{m}{10^{(1 + e)}}
\]</span></p>
<p>The exponent shifts the decimal point downwards, enabling a practical range from sub-0.001% values up to 1000.00%. Due to the decimal exponent scheme, some percentages may admit multiple valid representations; consuming code should treat the value as the decoded percentage rather than relying on a unique canonical encoding.</p>
<h1 id="test-coverage-report">Test coverage report</h1>
<p>All tests and fuzz tests executed successfully and were well-written. It was not possible to compile a coverage report because Foundry does not compile fuzz tests successfully when running coverage.</p>

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

Secure your system.
Request a service
Start Now