diff --git a/go.mod b/go.mod
index 680aeae38ca4edd1294355cfe02f54d947f3a74f..d55a842d65b3b1e32984c02fa8d7cbd1056d53fe 100644
--- a/go.mod
+++ b/go.mod
@@ -7,11 +7,11 @@ require (
 	github.com/hack-pad/go-indexeddb v0.2.0
 	github.com/pkg/errors v0.9.1
 	github.com/spf13/jwalterweatherman v1.1.0
-	gitlab.com/elixxir/client/v4 v4.3.12-0.20221219215743-62264017437e
-	gitlab.com/elixxir/crypto v0.0.7-0.20221219161351-7c3751afd8f2
+	gitlab.com/elixxir/client/v4 v4.3.12-0.20221221175633-6a18379afb0f
+	gitlab.com/elixxir/crypto v0.0.7-0.20221220181038-c77d1bf49838
 	gitlab.com/elixxir/primitives v0.0.3-0.20221214192222-988b44a6958a
 	gitlab.com/xx_network/crypto v0.0.5-0.20221121220724-8eefdbb0eb46
-	gitlab.com/xx_network/primitives v0.0.4-0.20221209210320-376735467d58
+	gitlab.com/xx_network/primitives v0.0.4-0.20221219230308-4b5550a9247d
 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
 )
 
diff --git a/go.sum b/go.sum
index 003ae101f705ae6473a5c2d1aa11d4987a3d3da2..945c34104c09b9d374ff809dc4babad69cf91363 100644
--- a/go.sum
+++ b/go.sum
@@ -1,49 +1,8 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
-cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
-cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
-cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
-cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
-cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
-cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
-cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
-cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
-cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
-cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
-cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
-filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
-git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221102223039-dc1f37d94e70 h1:p24wUpzdil0wgyFerGJM69fD5Xz9hsBDBK8f9m01pq8=
-git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221102223039-dc1f37d94e70/go.mod h1:uFKw2wmgtlYMdiIm08dM0Vj4XvX9ZKVCj71c8O7SAPo=
 git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221215181401-0b8a26d47532 h1:EH4TFLgXGgofV2MsUOgNDmn3X+qfhbQ2RV6zOYRaSdU=
 git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221215181401-0b8a26d47532/go.mod h1:uFKw2wmgtlYMdiIm08dM0Vj4XvX9ZKVCj71c8O7SAPo=
-git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221215201903-f66fe2cea35f h1:0/09N8iy4t3a//5z5VB1tNjmx6XnPxtcjpOGGPoVs5c=
-git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221215201903-f66fe2cea35f/go.mod h1:uFKw2wmgtlYMdiIm08dM0Vj4XvX9ZKVCj71c8O7SAPo=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
@@ -83,23 +42,17 @@ github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8
 github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/circl v1.2.0 h1:NheeISPSUcYftKlfrLuOo4T62FkmD4t4jviLfFFYaec=
 github.com/cloudflare/circl v1.2.0/go.mod h1:Ch2UgYr6ti2KTtlejELlROl0YIYj7SLjAC8M+INXlMk=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -118,22 +71,16 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
 github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
-github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
 github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -165,20 +112,11 @@ github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -198,33 +136,12 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -255,19 +172,14 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
 github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ=
 github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -280,8 +192,6 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
@@ -295,7 +205,6 @@ github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8
 github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -308,8 +217,6 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/liyue201/goqr v0.0.0-20200803022322-df443203d4ea h1:uyJ13zfy6l79CM3HnVhDalIyZ4RJAyVfDrbnfFeJoC4=
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
-github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
-github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@@ -328,8 +235,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
-github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -350,10 +255,6 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
-github.com/oasisprotocol/curve25519-voi v0.0.0-20221003100820-41fad3beba17 h1:lpwUgSIAfvJJ9sQ9BB//ZCjqzzFSuSg8mYOf+8L96+E=
-github.com/oasisprotocol/curve25519-voi v0.0.0-20221003100820-41fad3beba17/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s=
-github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4=
-github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs=
 github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
 github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
@@ -372,10 +273,6 @@ github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh
 github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
-github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
-github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
 github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
 github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -384,9 +281,6 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
-github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM=
-github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
-github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@@ -419,7 +313,6 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
 github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
 github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -438,38 +331,22 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
 github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
 github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
 github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
-github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
-github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
-github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
-github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
-github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
 github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
-github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
 github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs=
-github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0=
 github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w=
@@ -484,10 +361,6 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
 github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
 github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
@@ -496,78 +369,29 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
 github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f h1:yXGvNBqzZwAhDYlSnxPRbgor6JWoOt1Z7s3z1O9JR40=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k=
-gitlab.com/elixxir/client/v4 v4.3.9-0.20221208215024-325fafebf519 h1:nxGzvotSXP/7ekAWj0VpHcieXzxV/wxJ6DD4KG8aid8=
-gitlab.com/elixxir/client/v4 v4.3.9-0.20221208215024-325fafebf519/go.mod h1:ID5txokZGTr7l+xTAoEtQMSSdvNZUBntJAWTR81upds=
-gitlab.com/elixxir/client/v4 v4.3.9-0.20221210003613-b73478d56e0d h1:Ydy9DnxHrrCfHY2UI6//88wT9L2kKtXUuA6di7ER3Ew=
-gitlab.com/elixxir/client/v4 v4.3.9-0.20221210003613-b73478d56e0d/go.mod h1:76yQ2oAQgAIFsb71+sZXeb361RBEfOU7jjY8gtyXTgU=
-gitlab.com/elixxir/client/v4 v4.3.11 h1:LGXdAjnGdWbK1eVtrAn5Fwage7vrlrgPXsoEtUJ4Lyg=
-gitlab.com/elixxir/client/v4 v4.3.11/go.mod h1:gxRW2YXDxCzESBnYqMDKH2I25TGv226TDujdQno3JQw=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219162223-d8e2974631fd h1:/GmQucH2O1LLLQ0FrexmUMivW2BuMfLTXQ8n3nYPKj4=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219162223-d8e2974631fd/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219191501-3789240dd3ed h1:5Gahh0ZkYoJEFgqDm6IYhPQYsUBVmfexVLcxB5ewauQ=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219191501-3789240dd3ed/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219191912-e8cd5d26d6df h1:E+LeA/BoZVkAiqjJ09QkIHXeAld5guOoaTuFkR1kwtY=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219191912-e8cd5d26d6df/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219194340-7f6106b6ec9c h1:LP07xMoRjwngjY2CIr8+ArZ3r8sCXnDUNe6CWLLg9xU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219194340-7f6106b6ec9c/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219194906-a8842179cf63 h1:4Adk73psccchWDHeI9pm/uI/ztIwErU/3bnxCCUe9kA=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219194906-a8842179cf63/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219202220-4a509612689a h1:UR69fckejY5S1hjg/qkDLu+hi6rT0gYUPgq6fXYGC8k=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219202220-4a509612689a/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219212339-818b3e804db2 h1:G+yJqmvXOmCmskwRndMg5MS9hFXgeBhWCcPyDv+L99w=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219212339-818b3e804db2/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219214237-b1d228b3a2ee h1:STHVMACRZRSiC2+d5opRbbqwNp7jmOVemxbrPju6/mo=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219214237-b1d228b3a2ee/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219215313-24f256274d49 h1:CHKcCZ0RIsfF0/KnEmeq9ca4gDLLTDzkhCw29u/a+OY=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219215313-24f256274d49/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219215743-62264017437e h1:LoQu539ZiyEagrfrs8gaZ0w4IyjQomfZwSK/QVJ4ejA=
-gitlab.com/elixxir/client/v4 v4.3.12-0.20221219215743-62264017437e/go.mod h1:lwm2uYZQHy12rDtANimw02Hfws8osuVkCKN6snm/jCU=
-gitlab.com/elixxir/comms v0.0.4-0.20221110181420-84bca6216fe4 h1:bLRjVCyMVde4n2hTVgoyyIAWrKI4CevpChchkPeb6A0=
-gitlab.com/elixxir/comms v0.0.4-0.20221110181420-84bca6216fe4/go.mod h1:XhI2/CMng+xcH3mAs+1aPz29PSNu1079XMJ8V+xxihw=
+gitlab.com/elixxir/client/v4 v4.3.12-0.20221221175633-6a18379afb0f h1:VjS02HzpQN8a0g0dzxcH2ogmmzJeOntLfgX0tzSt4bE=
+gitlab.com/elixxir/client/v4 v4.3.12-0.20221221175633-6a18379afb0f/go.mod h1:rZcfB8jkloBkUqKsdUAifWaGmSmJyZUOmDKnqAwmias=
 gitlab.com/elixxir/comms v0.0.4-0.20221215214627-7807bfdde33a h1:DuqDqWc5cWjZ3qk98K1Bf9y1dYlyCeIigFmkHWDKc1Q=
 gitlab.com/elixxir/comms v0.0.4-0.20221215214627-7807bfdde33a/go.mod h1:B2Yek4mCbtN2aXZkyZcUffd3sTEZ5WgKD0mRBSVYtF8=
-gitlab.com/elixxir/crypto v0.0.7-0.20221208214832-13e2a751db1a h1:d514iJOaPmH2qjqUyI1N93UyEPTWvZ40LJiRPvQ89jw=
-gitlab.com/elixxir/crypto v0.0.7-0.20221208214832-13e2a751db1a/go.mod h1:fb6UMdmr0hVnzOU67hOZzTeS+wcQZ4pUtTO82039wGg=
-gitlab.com/elixxir/crypto v0.0.7-0.20221209195912-492ced8f7c92 h1:76JsxCk9Qwe1SFzYkrP42YVffhDcHXjwDBH/B3YS40U=
-gitlab.com/elixxir/crypto v0.0.7-0.20221209195912-492ced8f7c92/go.mod h1:fb6UMdmr0hVnzOU67hOZzTeS+wcQZ4pUtTO82039wGg=
-gitlab.com/elixxir/crypto v0.0.7-0.20221214192244-6783272c04a0 h1:dwCf7wKv2DCuYZZ394bSQWdUOXiABLsEyDvXZUOo83o=
-gitlab.com/elixxir/crypto v0.0.7-0.20221214192244-6783272c04a0/go.mod h1:oRh3AwveOEvpk9E3kRcMGK8fImcEnN0PY4jr9HDgQE8=
-gitlab.com/elixxir/crypto v0.0.7-0.20221219161351-7c3751afd8f2 h1:QPTL5+jHqfauN8WrmHMwvJ/d0Rbm/EY20Iggeu+NPvs=
-gitlab.com/elixxir/crypto v0.0.7-0.20221219161351-7c3751afd8f2/go.mod h1:7whUm4bnEdEoiVfMnu3TbHgvlrz0Ywp/Tekqg2Wl7vw=
+gitlab.com/elixxir/crypto v0.0.7-0.20221220181038-c77d1bf49838 h1:s93tL+O9LaHow14edbJF0/tAKGvKkoUJCeHPNtkB9iY=
+gitlab.com/elixxir/crypto v0.0.7-0.20221220181038-c77d1bf49838/go.mod h1:oRh3AwveOEvpk9E3kRcMGK8fImcEnN0PY4jr9HDgQE8=
 gitlab.com/elixxir/ekv v0.2.1 h1:dtwbt6KmAXG2Tik5d60iDz2fLhoFBgWwST03p7T+9Is=
 gitlab.com/elixxir/ekv v0.2.1/go.mod h1:USLD7xeDnuZEavygdrgzNEwZXeLQJK/w1a+htpN+JEU=
-gitlab.com/elixxir/primitives v0.0.3-0.20221114231218-cc461261a6af h1:xcPqknK1ehNb9xwcutTdoR0YgD7DC/ySh9z49tIpSxQ=
-gitlab.com/elixxir/primitives v0.0.3-0.20221114231218-cc461261a6af/go.mod h1:DUnCTXYKgjpro5+6ITySKIf+qzW2vhW40IVHMimdsqw=
 gitlab.com/elixxir/primitives v0.0.3-0.20221214192222-988b44a6958a h1:F17FfEjS+/uDI/TTYQD21S5JvNZ9+p9bieau2nyLCzo=
 gitlab.com/elixxir/primitives v0.0.3-0.20221214192222-988b44a6958a/go.mod h1:DUnCTXYKgjpro5+6ITySKIf+qzW2vhW40IVHMimdsqw=
-gitlab.com/xx_network/comms v0.0.4-0.20221207203143-462f82d6ec01 h1:0jkud7OWqneH9xEjDARnLspspxA3SDsNrbg8heY+wMQ=
-gitlab.com/xx_network/comms v0.0.4-0.20221207203143-462f82d6ec01/go.mod h1:+RfHgk75ywMvmucOpPS7rSUlsnbPyBuLsr13tsthUTE=
 gitlab.com/xx_network/comms v0.0.4-0.20221215214252-1275cef8760e h1:l+FiCBP2Lc1+cR6xwWDVDvSHnuzOaZFIRUEYGUwKGBA=
 gitlab.com/xx_network/comms v0.0.4-0.20221215214252-1275cef8760e/go.mod h1:FR/OyruSuob6+xzSZtk+rXlncbRr6nDKFypX3vwtkFc=
 gitlab.com/xx_network/crypto v0.0.5-0.20221121220724-8eefdbb0eb46 h1:6AHgUpWdJ72RVTTdJSvfThZiYTQNUnrPaTCl/EkRLpg=
 gitlab.com/xx_network/crypto v0.0.5-0.20221121220724-8eefdbb0eb46/go.mod h1:acWUBKCpae/XVaQF7J9RnLAlBT13i5r7gnON+mrIxBk=
-gitlab.com/xx_network/primitives v0.0.4-0.20221110180011-fd6ea3058225 h1:TAn87e6Zt9KwcSnWKyIul5eu8T0RHY9FDubCGs3G0dw=
-gitlab.com/xx_network/primitives v0.0.4-0.20221110180011-fd6ea3058225/go.mod h1:rP/2IsqIFHapuIB4mstXKItvwoJRQ9Wlms/NGeutHsk=
-gitlab.com/xx_network/primitives v0.0.4-0.20221209210320-376735467d58 h1:HpeUIf1gIIelLH3LHxEf3/GalecbbtZnOnIegJHALoc=
-gitlab.com/xx_network/primitives v0.0.4-0.20221209210320-376735467d58/go.mod h1:wUxbEBGOBJZ/RkAiVAltlC1uIlIrU0dE113Nq7HiOhw=
+gitlab.com/xx_network/primitives v0.0.4-0.20221219230308-4b5550a9247d h1:D9hEtiQ7xj0yFBkDkb4X4S95RfNoeXxtB1eE4UuFHtk=
+gitlab.com/xx_network/primitives v0.0.4-0.20221219230308-4b5550a9247d/go.mod h1:wUxbEBGOBJZ/RkAiVAltlC1uIlIrU0dE113Nq7HiOhw=
 gitlab.com/xx_network/ring v0.0.3-0.20220902183151-a7d3b15bc981 h1:1s0vX9BbkiD0IVXwr3LOaTBcq1wBrWcUWMBK0s8r0Z0=
 gitlab.com/xx_network/ring v0.0.3-0.20220902183151-a7d3b15bc981/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM=
-gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo=
-gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ=
-gitlab.com/yawning/nyquist.git v0.0.0-20221003103146-de5645224a22 h1:25fLWFlW+5awvcQhZj4drwVHP4Cmb+iZpfiS6LgE8f0=
-gitlab.com/yawning/nyquist.git v0.0.0-20221003103146-de5645224a22/go.mod h1:VvFd4eOUakA3ieUDzIpPT5GwkBTS/NKvIWr0SlNI8U4=
-gitlab.com/yawning/x448.git v0.0.0-20221003101044-617eb9b7d9b7 h1:ITrNVw6uSwSdEap0RR4us4RV1CHPBHvBZApENRcDk3c=
-gitlab.com/yawning/x448.git v0.0.0-20221003101044-617eb9b7d9b7/go.mod h1:BC2R0OW0tAYTMNLB4UMXwkk7WKokoDZP5n73hyLPyCo=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
 go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -585,27 +409,15 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -613,23 +425,11 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -642,58 +442,25 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c h1:JVAXQ10yGGVbSyoer5VILysz6YKjdNT2bsvlayjqhes=
 golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -707,67 +474,36 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220325203850-36772127a21f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
-golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220731174439-a90be440212d h1:Sv5ogFZatcgIMMtBSTTAgMYsicp25MXBubjXNDKwm80=
+golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -775,124 +511,30 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
-golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
-google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
-google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc h1:Nf+EdcTLHR8qDNN/KfkQL0u0ssxt9OhbaWCl5C0ucEI=
 google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@@ -900,23 +542,14 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
 google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
 google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
-google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
 google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -941,8 +574,6 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
-gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
-gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -954,25 +585,16 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
 nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
 nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
 src.agwa.name/tlshacks v0.0.0-20220518131152-d2c6f4e2b780 h1:iMW3HbLV3/OuK02FDW8qNC13i5o1uK079MGLH404rnQ=
diff --git a/indexedDb/channels/implementation.go b/indexedDb/channels/implementation.go
index 6bb3916f1e63de93f894532427e18efde93fb9ed..bc73bf68a34d25d3d611f31957f78d6c1095482f 100644
--- a/indexedDb/channels/implementation.go
+++ b/indexedDb/channels/implementation.go
@@ -42,6 +42,13 @@ type wasmModel struct {
 	updateMux         sync.Mutex
 }
 
+// DeleteMessage removes a message with the given messageID from storage.
+func (w *wasmModel) DeleteMessage(messageID cryptoChannel.MessageID) error {
+	msgId := js.ValueOf(base64.StdEncoding.EncodeToString(messageID.Bytes()))
+	return indexedDb.DeleteIndex(w.db, messageStoreName,
+		messageStoreMessageIndex, pkeyName, msgId)
+}
+
 // JoinChannel is called whenever a channel is joined locally.
 func (w *wasmModel) JoinChannel(channel *cryptoBroadcast.Channel) {
 	parentErr := errors.New("failed to JoinChannel")
@@ -78,35 +85,12 @@ func (w *wasmModel) JoinChannel(channel *cryptoBroadcast.Channel) {
 func (w *wasmModel) LeaveChannel(channelID *id.ID) {
 	parentErr := errors.New("failed to LeaveChannel")
 
-	// Prepare the Transaction
-	txn, err := w.db.Transaction(idb.TransactionReadWrite, channelsStoreName)
-	if err != nil {
-		jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
-			"Unable to create Transaction: %+v", err))
-		return
-	}
-	store, err := txn.ObjectStore(channelsStoreName)
+	// Delete the channel from storage
+	err := indexedDb.Delete(w.db, channelsStoreName,
+		js.ValueOf(channelID.String()))
 	if err != nil {
 		jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
-			"Unable to get ObjectStore: %+v", err))
-		return
-	}
-
-	// Perform the operation
-	_, err = store.Delete(js.ValueOf(channelID.String()))
-	if err != nil {
-		jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
-			"Unable to Delete Channel: %+v", err))
-		return
-	}
-
-	// Wait for the operation to return
-	ctx, cancel := indexedDb.NewContext()
-	err = txn.Await(ctx)
-	cancel()
-	if err != nil {
-		jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
-			"Deleting Channel failed: %+v", err))
+			"Unable to delete Channel: %+v", err))
 		return
 	}
 
@@ -171,7 +155,7 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID,
 	messageID message.ID, nickname, text string,
 	pubKey ed25519.PublicKey, dmToken uint32, codeset uint8,
 	timestamp time.Time, lease time.Duration, round rounds.Round,
-	mType channels.MessageType, status channels.SentStatus) uint64 {
+	mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 {
 	textBytes := []byte(text)
 	var err error
 
@@ -186,7 +170,8 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID,
 
 	msgToInsert := buildMessage(
 		channelID.Marshal(), messageID.Bytes(), nil, nickname,
-		textBytes, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType, status)
+		textBytes, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType,
+		hidden, status)
 
 	uuid, err := w.receiveHelper(msgToInsert, false)
 	if err != nil {
@@ -207,7 +192,7 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID,
 	messageID message.ID, replyTo message.ID,
 	nickname, text string, pubKey ed25519.PublicKey, dmToken uint32, codeset uint8,
 	timestamp time.Time, lease time.Duration, round rounds.Round,
-	mType channels.MessageType, status channels.SentStatus) uint64 {
+	mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 {
 	textBytes := []byte(text)
 	var err error
 
@@ -222,7 +207,7 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID,
 
 	msgToInsert := buildMessage(channelID.Marshal(), messageID.Bytes(),
 		replyTo.Bytes(), nickname, textBytes, pubKey, dmToken, codeset,
-		timestamp, lease, round.ID, mType, status)
+		timestamp, lease, round.ID, mType, hidden, status)
 
 	uuid, err := w.receiveHelper(msgToInsert, false)
 
@@ -243,7 +228,7 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID,
 	messageID message.ID, reactionTo message.ID,
 	nickname, reaction string, pubKey ed25519.PublicKey, dmToken uint32, codeset uint8,
 	timestamp time.Time, lease time.Duration, round rounds.Round,
-	mType channels.MessageType, status channels.SentStatus) uint64 {
+	mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 {
 	textBytes := []byte(reaction)
 	var err error
 
@@ -258,7 +243,8 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID,
 
 	msgToInsert := buildMessage(
 		channelID.Marshal(), messageID.Bytes(), reactionTo.Bytes(), nickname,
-		textBytes, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType, status)
+		textBytes, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType,
+		hidden, status)
 
 	uuid, err := w.receiveHelper(msgToInsert, false)
 	if err != nil {
@@ -268,15 +254,51 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID,
 	return uuid
 }
 
-// UpdateSentStatus is called whenever the [channels.SentStatus] of a message
-// has changed. At this point the message ID goes from empty/unknown to
-// populated.
+// The API needs to return the UUID of the modified message that can be
+// referenced at a later time.
 //
-// TODO: Potential race condition due to separate get/update operations.
-func (w *wasmModel) UpdateSentStatus(uuid uint64,
-	messageID message.ID, timestamp time.Time, round rounds.Round,
-	status channels.SentStatus) {
-	parentErr := errors.New("failed to UpdateSentStatus")
+// timestamp, round, pinned, and hidden are all nillable and may be updated
+// based upon the UUID at a later date. If a nil value is passed, then make
+// no update.
+func (w *wasmModel) UpdateFromMessageID(messageID cryptoChannel.MessageID,
+	timestamp *time.Time, round *rounds.Round, pinned, hidden *bool,
+	status *channels.SentStatus) uint64 {
+	parentErr := errors.New("failed to UpdateFromMessageID")
+
+	// FIXME: this is a bit of race condition without the mux.
+	//        This should be done via the transactions (i.e., make a
+	//        special version of receiveHelper)
+	w.updateMux.Lock()
+	defer w.updateMux.Unlock()
+
+	msgIDStr := base64.StdEncoding.EncodeToString(messageID.Marshal())
+	currentMsgObj, err := indexedDb.GetIndex(w.db, messageStoreName,
+		messageStoreMessageIndex, js.ValueOf(msgIDStr))
+	if err != nil {
+		jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
+			"Failed to get message by index: %+v", err))
+		return 0
+	}
+
+	currentMsg := utils.JsToJson(currentMsgObj)
+	uuid, err := w.updateMessage(currentMsg, &messageID, timestamp,
+		round, pinned, hidden, status)
+	if err != nil {
+		jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
+			"Unable to updateMessage: %+v", err))
+	}
+	return uuid
+}
+
+// UpdateFromUUID is called whenever a message at the UUID is modified.
+//
+// messageID, timestamp, round, pinned, and hidden are all nillable and may be
+// updated based upon the UUID at a later date. If a nil value is passed, then
+// make no update.
+func (w *wasmModel) UpdateFromUUID(uuid uint64,
+	messageID *cryptoChannel.MessageID, timestamp *time.Time,
+	round *rounds.Round, pinned, hidden *bool, status *channels.SentStatus) {
+	parentErr := errors.New("failed to UpdateFromUUID")
 
 	// FIXME: this is a bit of race condition without the mux.
 	//        This should be done via the transactions (i.e., make a
@@ -295,36 +317,59 @@ func (w *wasmModel) UpdateSentStatus(uuid uint64,
 		return
 	}
 
-	// Extract the existing Message and update the Status
-	newMessage := &Message{}
-	err = json.Unmarshal([]byte(utils.JsToJson(currentMsg)), newMessage)
+	_, err = w.updateMessage(utils.JsToJson(currentMsg), messageID, timestamp,
+		round, pinned, hidden, status)
 	if err != nil {
 		jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
-			"Could not JSON unmarshal message: %+v", err))
-		return
+			"Unable to updateMessage: %+v", err))
+	}
+}
+
+// updateMessage is a helper for updating a stored message.
+func (w *wasmModel) updateMessage(currentMsgJson string,
+	messageID *cryptoChannel.MessageID, timestamp *time.Time,
+	round *rounds.Round, pinned, hidden *bool,
+	status *channels.SentStatus) (uint64, error) {
+
+	newMessage := &Message{}
+	err := json.Unmarshal([]byte(currentMsgJson), newMessage)
+	if err != nil {
+		return 0, err
 	}
 
-	newMessage.Status = uint8(status)
-	if !messageID.Equals(message.ID{}) {
+	if status != nil {
+		newMessage.Status = uint8(*status)
+	}
+	if messageID != nil {
 		newMessage.MessageID = messageID.Bytes()
 	}
 
-	if round.ID != 0 {
+	if round != nil {
 		newMessage.Round = uint64(round.ID)
 	}
 
-	if !timestamp.Equal(time.Time{}) {
-		newMessage.Timestamp = timestamp
+	if timestamp != nil {
+		newMessage.Timestamp = *timestamp
+	}
+
+	if pinned != nil {
+		newMessage.Pinned = *pinned
+	}
+
+	if hidden != nil {
+		newMessage.Hidden = *hidden
 	}
 
 	// Store the updated Message
-	_, err = w.receiveHelper(newMessage, true)
+	uuid, err := w.receiveHelper(newMessage, true)
 	if err != nil {
-		jww.ERROR.Printf("%+v", errors.Wrap(parentErr, err.Error()))
+		return 0, err
 	}
 	channelID := &id.ID{}
 	copy(channelID[:], newMessage.ChannelID)
 	go w.receivedMessageCB(uuid, channelID, true)
+
+	return uuid, nil
 }
 
 // buildMessage is a private helper that converts typical [channels.EventModel]
@@ -336,7 +381,7 @@ func (w *wasmModel) UpdateSentStatus(uuid uint64,
 func buildMessage(channelID, messageID, parentID []byte, nickname string,
 	text []byte, pubKey ed25519.PublicKey, dmToken uint32, codeset uint8, timestamp time.Time,
 	lease time.Duration, round id.Round, mType channels.MessageType,
-	status channels.SentStatus) *Message {
+	pinned, hidden bool, status channels.SentStatus) *Message {
 	return &Message{
 		MessageID:       messageID,
 		Nickname:        nickname,
@@ -345,8 +390,8 @@ func buildMessage(channelID, messageID, parentID []byte, nickname string,
 		Timestamp:       timestamp,
 		Lease:           lease,
 		Status:          uint8(status),
-		Hidden:          false,
-		Pinned:          false,
+		Hidden:          hidden,
+		Pinned:          pinned,
 		Text:            text,
 		Type:            uint16(mType),
 		Round:           uint64(round),
@@ -387,9 +432,9 @@ func (w *wasmModel) receiveHelper(newMessage *Message, isUpdate bool) (uint64,
 	if result.IsUndefined() {
 		msgID := message.ID{}
 		copy(msgID[:], newMessage.MessageID)
-		uuid, errLookup := w.msgIDLookup(msgID)
-		if uuid != 0 && errLookup == nil {
-			return uuid, nil
+		msg, errLookup := w.msgIDLookup(msgID)
+		if msg.ID != 0 && errLookup == nil {
+			return msg.ID, nil
 		}
 		return 0, errors.Errorf("uuid lookup failure: %+v", err)
 	}
@@ -399,19 +444,66 @@ func (w *wasmModel) receiveHelper(newMessage *Message, isUpdate bool) (uint64,
 	return uuid, nil
 }
 
+// GetMessage returns the message with the given [channel.MessageID].
+func (w *wasmModel) GetMessage(messageID cryptoChannel.MessageID) (channels.ModelMessage, error) {
+	lookupResult, err := w.msgIDLookup(messageID)
+	if err != nil {
+		return channels.ModelMessage{}, err
+	}
+
+	var channelId *id.ID
+	if lookupResult.ChannelID != nil {
+		channelId, err = id.Unmarshal(lookupResult.ChannelID)
+		if err != nil {
+			return channels.ModelMessage{}, err
+		}
+	}
+
+	var parentMsgId cryptoChannel.MessageID
+	if lookupResult.ParentMessageID != nil {
+		parentMsgId, err = cryptoChannel.UnmarshalMessageID(lookupResult.ParentMessageID)
+		if err != nil {
+			return channels.ModelMessage{}, err
+		}
+	}
+
+	return channels.ModelMessage{
+		UUID:            lookupResult.ID,
+		Nickname:        lookupResult.Nickname,
+		MessageID:       messageID,
+		ChannelID:       channelId,
+		ParentMessageID: parentMsgId,
+		Timestamp:       lookupResult.Timestamp,
+		Lease:           lookupResult.Lease,
+		Status:          channels.SentStatus(lookupResult.Status),
+		Hidden:          lookupResult.Hidden,
+		Pinned:          lookupResult.Pinned,
+		Content:         lookupResult.Text,
+		Type:            channels.MessageType(lookupResult.Type),
+		Round:           id.Round(lookupResult.Round),
+		PubKey:          lookupResult.Pubkey,
+		CodesetVersion:  lookupResult.CodesetVersion,
+	}, nil
+}
+
 // msgIDLookup gets the UUID of the Message with the given messageID.
-func (w *wasmModel) msgIDLookup(messageID message.ID) (uint64,
+func (w *wasmModel) msgIDLookup(messageID message.ID) (*Message,
 	error) {
 	msgIDStr := js.ValueOf(base64.StdEncoding.EncodeToString(messageID.Bytes()))
 	resultObj, err := indexedDb.GetIndex(w.db, messageStoreName,
 		messageStoreMessageIndex, msgIDStr)
 	if err != nil {
-		return 0, err
+		return nil, err
+	} else if resultObj.IsUndefined() {
+		return nil, errors.Errorf("no message for %s found", msgIDStr)
 	}
 
-	uuid := uint64(0)
-	if !resultObj.IsUndefined() {
-		uuid = uint64(resultObj.Get("id").Int())
+	// Process result into string
+	resultMsg := &Message{}
+	err = json.Unmarshal([]byte(utils.JsToJson(resultObj)), resultMsg)
+	if err != nil {
+		return nil, err
 	}
-	return uuid, nil
+	return resultMsg, nil
+
 }
diff --git a/indexedDb/channels/implementation_test.go b/indexedDb/channels/implementation_test.go
index 8f240d9f5f5f949f9501a7c8c05e3249f78f5b5f..689133d3002b0567bc50545c6716d88273355601 100644
--- a/indexedDb/channels/implementation_test.go
+++ b/indexedDb/channels/implementation_test.go
@@ -12,23 +12,22 @@ package channels
 import (
 	"encoding/json"
 	"fmt"
-	"os"
-	"strconv"
-	"testing"
-	"time"
-
 	"github.com/hack-pad/go-indexeddb/idb"
 	"gitlab.com/elixxir/xxdk-wasm/indexedDb"
 	"gitlab.com/elixxir/xxdk-wasm/storage"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/primitives/netTime"
+	"os"
+	"strconv"
+	"testing"
+	"time"
 
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/v4/channels"
 	"gitlab.com/elixxir/client/v4/cmix/rounds"
 	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	"gitlab.com/elixxir/crypto/channel"
 	cryptoChannel "gitlab.com/elixxir/crypto/channel"
-	"gitlab.com/elixxir/crypto/message"
 	"gitlab.com/xx_network/primitives/id"
 )
 
@@ -54,32 +53,75 @@ func TestWasmModel_msgIDLookup(t *testing.T) {
 
 			storage.GetLocalStorage().Clear()
 			testString := "test"
-			testMsgId := message.DeriveChannelMessageID(&id.ID{1},
-				0, []byte(testString))
+			testMsgId := channel.MakeMessageID([]byte(testString), &id.ID{1})
 			eventModel, err := newWASMModel(testString, c, dummyCallback)
 			if err != nil {
 				t.Fatalf("%+v", err)
 			}
 
 			testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil,
-				testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, netTime.Now(),
-				time.Second, 0, 0, channels.Sent)
+				testString, []byte(testString), []byte{8, 6, 7, 5}, 0,
+				netTime.Now(), time.Second, 0, 0, false, false, channels.Sent)
 			_, err = eventModel.receiveHelper(testMsg, false)
 			if err != nil {
 				t.Fatalf("%+v", err)
 			}
 
-			uuid, err := eventModel.msgIDLookup(testMsgId)
+			msg, err := eventModel.msgIDLookup(testMsgId)
 			if err != nil {
 				t.Fatalf("%+v", err)
 			}
-			if uuid == 0 {
+			if msg.ID == 0 {
 				t.Fatalf("Expected to get a UUID!")
 			}
 		})
 	}
 }
 
+// Happy path, insert message and delete it
+func TestWasmModel_DeleteMessage(t *testing.T) {
+	storage.GetLocalStorage().Clear()
+	testString := "test"
+	testMsgId := channel.MakeMessageID([]byte(testString), &id.ID{1})
+	eventModel, err := newWASMModel(testString, nil, dummyCallback)
+	if err != nil {
+		t.Fatalf("%+v", err)
+	}
+
+	// Insert a message
+	testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil,
+		testString, []byte(testString), []byte{8, 6, 7, 5}, 0, netTime.Now(),
+		time.Second, 0, 0, false, false, channels.Sent)
+	_, err = eventModel.receiveHelper(testMsg, false)
+	if err != nil {
+		t.Fatalf("%+v", err)
+	}
+
+	// Check the resulting status
+	results, err := indexedDb.Dump(eventModel.db, messageStoreName)
+	if err != nil {
+		t.Fatalf("%+v", err)
+	}
+	if len(results) != 1 {
+		t.Fatalf("Expected 1 message to exist")
+	}
+
+	// Delete the message
+	err = eventModel.DeleteMessage(testMsgId)
+	if err != nil {
+		t.Fatalf("%+v", err)
+	}
+
+	// Check the resulting status
+	results, err = indexedDb.Dump(eventModel.db, messageStoreName)
+	if err != nil {
+		t.Fatalf("%+v", err)
+	}
+	if len(results) != 0 {
+		t.Fatalf("Expected no messages to exist")
+	}
+}
+
 // Test wasmModel.UpdateSentStatus happy path and ensure fields don't change.
 func Test_wasmModel_UpdateSentStatus(t *testing.T) {
 	cipher, err := cryptoChannel.NewCipher([]byte("testpass"), []byte("testsalt"), 128, csprng.NewSystemRNG())
@@ -94,8 +136,7 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) {
 		t.Run(fmt.Sprintf("Test_wasmModel_UpdateSentStatus%s", cs), func(t *testing.T) {
 			storage.GetLocalStorage().Clear()
 			testString := "test"
-			testMsgId := message.DeriveChannelMessageID(&id.ID{1},
-				0, []byte(testString))
+			testMsgId := channel.MakeMessageID([]byte(testString), &id.ID{1})
 			eventModel, err := newWASMModel(testString, c, dummyCallback)
 			if err != nil {
 				t.Fatalf("%+v", err)
@@ -103,8 +144,8 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) {
 
 			// Store a test message
 			testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil,
-				testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, netTime.Now(),
-				time.Second, 0, 0, channels.Sent)
+				testString, []byte(testString), []byte{8, 6, 7, 5}, 0, netTime.Now(),
+				time.Second, 0, 0, false, false, channels.Sent)
 			uuid, err := eventModel.receiveHelper(testMsg, false)
 			if err != nil {
 				t.Fatalf("%+v", err)
@@ -121,8 +162,8 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) {
 
 			// Update the sentStatus
 			expectedStatus := channels.Failed
-			eventModel.UpdateSentStatus(uuid, testMsgId, netTime.Now(),
-				rounds.Round{ID: 8675309}, expectedStatus)
+			eventModel.UpdateFromUUID(
+				uuid, nil, nil, nil, nil, nil, &expectedStatus)
 
 			// Check the resulting status
 			results, err = indexedDb.Dump(eventModel.db, messageStoreName)
@@ -224,12 +265,12 @@ func Test_wasmModel_UUIDTest(t *testing.T) {
 			for i := 0; i < 10; i++ {
 				// Store a test message
 				channelID := id.NewIdFromBytes([]byte(testString), t)
-				msgID := message.ID{}
+				msgID := channel.MessageID{}
 				copy(msgID[:], testString+fmt.Sprintf("%d", i))
 				rnd := rounds.Round{ID: id.Round(42)}
 				uuid := eventModel.ReceiveMessage(channelID, msgID, "test",
-					testString+fmt.Sprintf("%d", i), []byte{8, 6, 7, 5}, 0, 0,
-					netTime.Now(), time.Hour, rnd, 0, channels.Sent)
+					testString+fmt.Sprintf("%d", i), []byte{8, 6, 7, 5}, 0,
+					netTime.Now(), time.Hour, rnd, 0, channels.Sent, false)
 				uuids[i] = uuid
 			}
 
@@ -266,15 +307,15 @@ func Test_wasmModel_DuplicateReceives(t *testing.T) {
 
 			uuids := make([]uint64, 10)
 
-			msgID := message.ID{}
+			msgID := channel.MessageID{}
 			copy(msgID[:], testString)
 			for i := 0; i < 10; i++ {
 				// Store a test message
 				channelID := id.NewIdFromBytes([]byte(testString), t)
 				rnd := rounds.Round{ID: id.Round(42)}
 				uuid := eventModel.ReceiveMessage(channelID, msgID, "test",
-					testString+fmt.Sprintf("%d", i), []byte{8, 6, 7, 5}, 0, 0,
-					netTime.Now(), time.Hour, rnd, 0, channels.Sent)
+					testString+fmt.Sprintf("%d", i), []byte{8, 6, 7, 5}, 0,
+					netTime.Now(), time.Hour, rnd, 0, channels.Sent, false)
 				uuids[i] = uuid
 			}
 
@@ -288,7 +329,6 @@ func Test_wasmModel_DuplicateReceives(t *testing.T) {
 			}
 		})
 	}
-
 }
 
 // Happy path: Inserts many messages, deletes some, and checks that the final
@@ -327,11 +367,10 @@ func Test_wasmModel_deleteMsgByChannel(t *testing.T) {
 					thisChannel = keepChannel
 				}
 
-				testMsgId := message.DeriveChannelMessageID(
-					&id.ID{1}, 0, []byte(testStr))
+				testMsgId := channel.MakeMessageID([]byte(testStr), &id.ID{1})
 				eventModel.ReceiveMessage(thisChannel, testMsgId, testStr, testStr,
-					[]byte{8, 6, 7, 5}, 0, 0, netTime.Now(), time.Second,
-					rounds.Round{ID: id.Round(0)}, 0, channels.Sent)
+					[]byte{8, 6, 7, 5}, 0, netTime.Now(), time.Second,
+					rounds.Round{ID: id.Round(0)}, 0, channels.Sent, false)
 			}
 
 			// Check pre-results
@@ -402,11 +441,10 @@ func TestWasmModel_receiveHelper_UniqueIndex(t *testing.T) {
 			}
 
 			// First message insert should succeed
-			testMsgId := message.DeriveChannelMessageID(&id.ID{1},
-				0, []byte(testString))
+			testMsgId := channel.MakeMessageID([]byte(testString), &id.ID{1})
 			testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil,
-				testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, netTime.Now(),
-				time.Second, 0, 0, channels.Sent)
+				testString, []byte(testString), []byte{8, 6, 7, 5}, 0,
+				netTime.Now(), time.Second, 0, 0, false, false, channels.Sent)
 			_, err = eventModel.receiveHelper(testMsg, false)
 			if err != nil {
 				t.Fatal(err)
@@ -426,11 +464,10 @@ func TestWasmModel_receiveHelper_UniqueIndex(t *testing.T) {
 			}
 
 			// Now insert a message with a different message ID from the first
-			testMsgId2 := message.DeriveChannelMessageID(&id.ID{1},
-				0, []byte(testString))
+			testMsgId2 := channel.MakeMessageID([]byte(testString), &id.ID{2})
 			testMsg = buildMessage([]byte(testString), testMsgId2.Bytes(), nil,
-				testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, netTime.Now(),
-				time.Second, 0, 0, channels.Sent)
+				testString, []byte(testString), []byte{8, 6, 7, 5}, 0,
+				netTime.Now(), time.Second, 0, 0, false, false, channels.Sent)
 			primaryKey, err := eventModel.receiveHelper(testMsg, false)
 			if err != nil {
 				t.Fatal(err)
diff --git a/indexedDb/utils.go b/indexedDb/utils.go
index 5af14e999a3d7f073ba820a69e842593bd49aab1..4b32064ae84254a42112c78feb36510c2501376d 100644
--- a/indexedDb/utils.go
+++ b/indexedDb/utils.go
@@ -36,6 +36,7 @@ func NewContext() (context.Context, context.CancelFunc) {
 }
 
 // Get is a generic helper for getting values from the given [idb.ObjectStore].
+// Only usable by primary key.
 func Get(db *idb.Database, objectStoreName string, key js.Value) (js.Value, error) {
 	parentErr := errors.Errorf("failed to Get %s/%s", objectStoreName, key)
 
@@ -78,7 +79,7 @@ func Get(db *idb.Database, objectStoreName string, key js.Value) (js.Value, erro
 
 // GetIndex is a generic helper for getting values from the given
 // [idb.ObjectStore] using the given [idb.Index].
-func GetIndex(db *idb.Database, objectStoreName string,
+func GetIndex(db *idb.Database, objectStoreName,
 	indexName string, key js.Value) (js.Value, error) {
 	parentErr := errors.Errorf("failed to GetIndex %s/%s/%s",
 		objectStoreName, indexName, key)
@@ -151,17 +152,18 @@ func Put(db *idb.Database, objectStoreName string, value js.Value) (js.Value, er
 	if err != nil {
 		return js.Undefined(), errors.Errorf("Putting value failed: %+v", err)
 	}
-	jww.DEBUG.Printf("Successfully put value in %s: %v",
+	jww.DEBUG.Printf("Successfully put value in %s: %s",
 		objectStoreName, utils.JsToJson(value))
 	return result, nil
 }
 
 // Delete is a generic helper for removing values from the given [idb.ObjectStore].
+// Only usable by primary key.
 func Delete(db *idb.Database, objectStoreName string, key js.Value) error {
 	parentErr := errors.Errorf("failed to Delete %s/%s", objectStoreName, key)
 
 	// Prepare the Transaction
-	txn, err := db.Transaction(idb.TransactionReadOnly, objectStoreName)
+	txn, err := db.Transaction(idb.TransactionReadWrite, objectStoreName)
 	if err != nil {
 		return errors.WithMessagef(parentErr,
 			"Unable to create Transaction: %+v", err)
@@ -173,20 +175,44 @@ func Delete(db *idb.Database, objectStoreName string, key js.Value) error {
 	}
 
 	// Perform the operation
-	deleteRequest, err := store.Delete(key)
+	_, err = store.Delete(key)
 	if err != nil {
 		return errors.WithMessagef(parentErr,
-			"Unable to Get from ObjectStore: %+v", err)
+			"Unable to Delete from ObjectStore: %+v", err)
 	}
 
 	// Wait for the operation to return
 	ctx, cancel := NewContext()
-	err = deleteRequest.Await(ctx)
+	err = txn.Await(ctx)
 	cancel()
 	if err != nil {
 		return errors.WithMessagef(parentErr,
-			"Unable to delete from ObjectStore: %+v", err)
+			"Unable to Delete from ObjectStore: %+v", err)
 	}
+	jww.DEBUG.Printf("Successfully deleted value at %s/%s",
+		objectStoreName, utils.JsToJson(key))
+	return nil
+}
+
+// DeleteIndex is a generic helper for removing values from the
+// given [idb.ObjectStore] using the given [idb.Index]. Requires passing
+// in the name of the primary key for the store.
+func DeleteIndex(db *idb.Database, objectStoreName,
+	indexName, pkeyName string, key js.Value) error {
+	parentErr := errors.Errorf("failed to DeleteIndex %s/%s", objectStoreName, key)
+
+	value, err := GetIndex(db, objectStoreName, indexName, key)
+	if err != nil {
+		return errors.WithMessagef(parentErr, "%+v", err)
+	}
+
+	err = Delete(db, objectStoreName, value.Get(pkeyName))
+	if err != nil {
+		return errors.WithMessagef(parentErr, "%+v", err)
+	}
+
+	jww.DEBUG.Printf("Successfully deleted value at %s/%s/%s",
+		objectStoreName, indexName, utils.JsToJson(key))
 	return nil
 }
 
diff --git a/main.go b/main.go
index d18364cc74455d2b2c68b1b97e423d8c68d4025e..de379dbdbf5eb3132e8cc546df5a6b601665e5e6 100644
--- a/main.go
+++ b/main.go
@@ -78,14 +78,12 @@ func main() {
 		js.FuncOf(wasm.LoadChannelsManagerWithIndexedDbUnsafe))
 	js.Global().Set("NewChannelsManagerWithIndexedDbUnsafe",
 		js.FuncOf(wasm.NewChannelsManagerWithIndexedDbUnsafe))
-	js.Global().Set("GenerateChannel", js.FuncOf(wasm.GenerateChannel))
-	js.Global().Set("GetSavedChannelPrivateKeyUNSAFE",
-		js.FuncOf(wasm.GetSavedChannelPrivateKeyUNSAFE))
 	js.Global().Set("DecodePublicURL", js.FuncOf(wasm.DecodePublicURL))
 	js.Global().Set("DecodePrivateURL", js.FuncOf(wasm.DecodePrivateURL))
 	js.Global().Set("GetChannelJSON", js.FuncOf(wasm.GetChannelJSON))
 	js.Global().Set("GetChannelInfo", js.FuncOf(wasm.GetChannelInfo))
 	js.Global().Set("GetShareUrlType", js.FuncOf(wasm.GetShareUrlType))
+	js.Global().Set("ValidForever", js.FuncOf(wasm.ValidForever))
 	js.Global().Set("IsNicknameValid", js.FuncOf(wasm.IsNicknameValid))
 	js.Global().Set("NewChannelsDatabaseCipher",
 		js.FuncOf(wasm.NewChannelsDatabaseCipher))
diff --git a/utils/utils.go b/utils/utils.go
index 19399f5a62c5f41269739440d0a9948a7c244200..cb1e46f3859695e7c77fbf0c9403eb24b7b10ff4 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -74,9 +74,11 @@ func CreatePromise(f PromiseFn) any {
 	return Promise.New(handler)
 }
 
-// Await waits on a Javascript value. It returns the results of the then and
-// catch functions once it resolves.
-func Await(awaitable js.Value) ([]js.Value, []js.Value) {
+// Await waits on a Javascript value. It blocks until the awaitable successfully
+// resolves to the result or rejects to err.
+//
+// If there is a result, err will be nil and vice versa.
+func Await(awaitable js.Value) (result []js.Value, err []js.Value) {
 	then := make(chan []js.Value)
 	defer close(then)
 	thenFunc := js.FuncOf(func(this js.Value, args []js.Value) any {
@@ -96,9 +98,9 @@ func Await(awaitable js.Value) ([]js.Value, []js.Value) {
 	awaitable.Call("then", thenFunc).Call("catch", catchFunc)
 
 	select {
-	case result := <-then:
+	case result = <-then:
 		return result, nil
-	case err := <-catch:
+	case err = <-catch:
 		return nil, err
 	}
 }
diff --git a/wasm/channels.go b/wasm/channels.go
index 66dd9e656a156c275d692a7a7bfb7ca2efadaf7c..d32737321c0efbab9ff732917b185a7b2cfbea99 100644
--- a/wasm/channels.go
+++ b/wasm/channels.go
@@ -11,7 +11,10 @@ package wasm
 
 import (
 	"encoding/base64"
-	"gitlab.com/elixxir/xxdk-wasm/indexedDb/channels"
+	"encoding/json"
+	"errors"
+	"gitlab.com/elixxir/client/v4/channels"
+	channelsDb "gitlab.com/elixxir/xxdk-wasm/indexedDb/channels"
 	"gitlab.com/xx_network/primitives/id"
 	"sync"
 	"syscall/js"
@@ -36,11 +39,12 @@ func newChannelsManagerJS(api *bindings.ChannelsManager) map[string]any {
 	cm := ChannelsManager{api}
 	channelsManagerMap := map[string]any{
 		// Basic Channel API
-		"GetID":         js.FuncOf(cm.GetID),
-		"JoinChannel":   js.FuncOf(cm.JoinChannel),
-		"GetChannels":   js.FuncOf(cm.GetChannels),
-		"LeaveChannel":  js.FuncOf(cm.LeaveChannel),
-		"ReplayChannel": js.FuncOf(cm.ReplayChannel),
+		"GetID":           js.FuncOf(cm.GetID),
+		"GenerateChannel": js.FuncOf(cm.GenerateChannel),
+		"JoinChannel":     js.FuncOf(cm.JoinChannel),
+		"GetChannels":     js.FuncOf(cm.GetChannels),
+		"LeaveChannel":    js.FuncOf(cm.LeaveChannel),
+		"ReplayChannel":   js.FuncOf(cm.ReplayChannel),
 
 		// Share URL
 		"GetShareURL": js.FuncOf(cm.GetShareURL),
@@ -51,12 +55,22 @@ func newChannelsManagerJS(api *bindings.ChannelsManager) map[string]any {
 		"SendMessage":           js.FuncOf(cm.SendMessage),
 		"SendReply":             js.FuncOf(cm.SendReply),
 		"SendReaction":          js.FuncOf(cm.SendReaction),
+		"DeleteMessage":         js.FuncOf(cm.DeleteMessage),
+		"PinMessage":            js.FuncOf(cm.PinMessage),
+		"MuteUser":              js.FuncOf(cm.MuteUser),
 		"GetIdentity":           js.FuncOf(cm.GetIdentity),
 		"ExportPrivateIdentity": js.FuncOf(cm.ExportPrivateIdentity),
 		"GetStorageTag":         js.FuncOf(cm.GetStorageTag),
 		"SetNickname":           js.FuncOf(cm.SetNickname),
 		"DeleteNickname":        js.FuncOf(cm.DeleteNickname),
 		"GetNickname":           js.FuncOf(cm.GetNickname),
+		"Muted":                 js.FuncOf(cm.Muted),
+		"GetMutedUsers":         js.FuncOf(cm.GetMutedUsers),
+		"IsChannelAdmin":        js.FuncOf(cm.IsChannelAdmin),
+		"ExportChannelAdminKey": js.FuncOf(cm.ExportChannelAdminKey),
+		"VerifyChannelAdminKey": js.FuncOf(cm.VerifyChannelAdminKey),
+		"ImportChannelAdminKey": js.FuncOf(cm.ImportChannelAdminKey),
+		"DeleteChannelAdminKey": js.FuncOf(cm.DeleteChannelAdminKey),
 
 		// Channel Receiving Logic and Callback Registration
 		"RegisterReceiveHandler": js.FuncOf(cm.RegisterReceiveHandler),
@@ -70,16 +84,19 @@ func newChannelsManagerJS(api *bindings.ChannelsManager) map[string]any {
 //
 // Returns:
 //   - Tracker ID (int).
-func (ch *ChannelsManager) GetID(js.Value, []js.Value) any {
-	return ch.api.GetID()
+func (cm *ChannelsManager) GetID(js.Value, []js.Value) any {
+	return cm.api.GetID()
 }
 
 // GenerateChannelIdentity creates a new private channel identity
-// ([channel.PrivateIdentity]). The public component can be retrieved as JSON
-// via [GetPublicChannelIdentityFromPrivate].
+// ([channel.PrivateIdentity]) from scratch and assigns it a codename.
+//
+// The public component can be retrieved as JSON via
+// [GetPublicChannelIdentityFromPrivate].
 //
 // Parameters:
-//   - args[0] - ID of [Cmix] object in tracker (int).
+//   - args[0] - ID of [Cmix] object in tracker (int). This can be retrieved
+//     using [Cmix.GetID].
 //
 // Returns:
 //   - Marshalled bytes of [channel.PrivateIdentity] (Uint8Array).
@@ -97,8 +114,8 @@ func GenerateChannelIdentity(_ js.Value, args []js.Value) any {
 // identityMap stores identities previously generated by ConstructIdentity.
 var identityMap sync.Map
 
-// ConstructIdentity constructs a [channel.Identity] from a user's public key
-// and codeset version.
+// ConstructIdentity creates a codename in a public [channel.Identity] from an
+// extant identity for a given codeset version.
 //
 // Parameters:
 //   - args[0] - The Ed25519 public key (Uint8Array).
@@ -157,7 +174,8 @@ func constructIdentity(_ js.Value, args []js.Value) any {
 //
 // Parameters:
 //   - args[0] - The password used to encrypt the identity (string).
-//   - args[2] - The encrypted data (Uint8Array).
+//   - args[2] - The encrypted data from [ChannelsManager.ExportPrivateIdentity]
+//     (Uint8Array).
 //
 // Returns:
 //   - JSON of [channel.PrivateIdentity] (Uint8Array).
@@ -202,7 +220,7 @@ func GetPublicChannelIdentity(_ js.Value, args []js.Value) any {
 //
 // Parameters:
 //   - args[0] - Bytes of the private identity
-//     (channel.PrivateIdentity]) (Uint8Array).
+//     ([channel.PrivateIdentity]) (Uint8Array).
 //
 // Returns:
 //   - JSON of the public identity ([channel.Identity]) (Uint8Array).
@@ -220,26 +238,6 @@ func GetPublicChannelIdentityFromPrivate(_ js.Value, args []js.Value) any {
 	return utils.CopyBytesToJS(identity)
 }
 
-// eventModelBuilder adheres to the [bindings.EventModelBuilder] interface.
-type eventModelBuilder struct {
-	build func(args ...any) js.Value
-}
-
-// Build initializes and returns the event model.  It wraps a Javascript object
-// that has all the methods in [bindings.EventModel] to make it adhere to the Go
-// interface [bindings.EventModel].
-func (emb *eventModelBuilder) Build(path string) bindings.EventModel {
-	emJs := emb.build(path)
-	return &eventModel{
-		joinChannel:      utils.WrapCB(emJs, "JoinChannel"),
-		leaveChannel:     utils.WrapCB(emJs, "LeaveChannel"),
-		receiveMessage:   utils.WrapCB(emJs, "ReceiveMessage"),
-		receiveReply:     utils.WrapCB(emJs, "ReceiveReply"),
-		receiveReaction:  utils.WrapCB(emJs, "ReceiveReaction"),
-		updateSentStatus: utils.WrapCB(emJs, "UpdateSentStatus"),
-	}
-}
-
 // NewChannelsManager creates a new [ChannelsManager] from a new private
 // identity ([channel.PrivateIdentity]).
 //
@@ -274,7 +272,8 @@ func NewChannelsManager(_ js.Value, args []js.Value) any {
 	return newChannelsManagerJS(cm)
 }
 
-// LoadChannelsManager loads an existing [ChannelsManager].
+// LoadChannelsManager loads an existing [ChannelsManager] for the given storage
+// tag.
 //
 // This is for loading a manager for an identity that has already been created.
 // The channel manager should have previously been created with
@@ -394,7 +393,7 @@ func newChannelsManagerWithIndexedDb(cmixID int, privateIdentity []byte,
 		cb.Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal()), update)
 	}
 
-	model := channels.NewWASMEventModelBuilder(cipher, messageReceivedCB)
+	model := channelsDb.NewWASMEventModelBuilder(cipher, messageReceivedCB)
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		cm, err := bindings.NewChannelsManagerGoEventModel(
@@ -493,7 +492,7 @@ func loadChannelsManagerWithIndexedDb(cmixID int, storageTag string,
 		cb.Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal()), updated)
 	}
 
-	model := channels.NewWASMEventModelBuilder(cipher, messageReceivedCB)
+	model := channelsDb.NewWASMEventModelBuilder(cipher, messageReceivedCB)
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		cm, err := bindings.LoadChannelsManagerGoEventModel(
@@ -508,76 +507,9 @@ func loadChannelsManagerWithIndexedDb(cmixID int, storageTag string,
 	return utils.CreatePromise(promiseFn)
 }
 
-// GenerateChannel is used to create a channel a new channel of which you are
-// the admin. It is only for making new channels, not joining existing ones.
-//
-// It returns a pretty print of the channel and the private key.
-//
-// The name cannot be longer that __ characters. The description cannot be
-// longer than __ and can only use ______ characters.
-//
-// Parameters:
-//   - args[0] - ID of [Cmix] object in tracker (int).
-//   - args[1] - The name of the new channel (string). The name must be between
-//     3 and 24 characters inclusive. It can only include upper and lowercase
-//     unicode letters, digits 0 through 9, and underscores (_). It cannot be
-//     changed once a channel is created.
-//   - args[2] - The description of a channel (string). The description is
-//     optional but cannot be longer than 144 characters and can include all
-//     unicode characters. It cannot be changed once a channel is created.
-//   - args[3] - The [broadcast.PrivacyLevel] of the channel (int). 0 = public,
-//     1 = private, and 2 = secret. Refer to the comment below for more
-//     information.
-//
-// Returns:
-//   - JSON of [bindings.ChannelGeneration], which describes a generated
-//     channel. It contains both the public channel info and the private key for
-//     the channel in PEM format (Uint8Array).
-//   - Throws a TypeError if generating the channel fails.
-//
-// The [broadcast.PrivacyLevel] of a channel indicates the level of channel
-// information revealed when sharing it via URL. For any channel besides public
-// channels, the secret information is encrypted and a password is required to
-// share and join a channel.
-//   - A privacy level of [broadcast.Public] reveals all the information
-//     including the name, description, privacy level, public key and salt.
-//   - A privacy level of [broadcast.Private] reveals only the name and
-//     description.
-//   - A privacy level of [broadcast.Secret] reveals nothing.
-func GenerateChannel(_ js.Value, args []js.Value) any {
-	gen, err := bindings.GenerateChannel(
-		args[0].Int(), args[1].String(), args[2].String(), args[3].Int())
-	if err != nil {
-		utils.Throw(utils.TypeError, err)
-		return nil
-	}
-
-	return utils.CopyBytesToJS(gen)
-}
-
-// GetSavedChannelPrivateKeyUNSAFE loads the private key from storage for the
-// given channel ID.
-//
-// NOTE: This function is unsafe and only for debugging purposes only.
-//
-// Parameters:
-//   - args[0] - ID of [Cmix] object in tracker (int).
-//   - args[1] - The [id.ID] of the channel in base 64 encoding (string).
-//
-// Returns:
-//   - The PEM file of the private key (string).
-//   - Throws a TypeError if retrieving the [Cmix] object or the private key
-//     fails.
-func GetSavedChannelPrivateKeyUNSAFE(_ js.Value, args []js.Value) any {
-	privKey, err := bindings.GetSavedChannelPrivateKeyUNSAFE(
-		args[0].Int(), args[1].String())
-	if err != nil {
-		utils.Throw(utils.TypeError, err)
-		return nil
-	}
-
-	return privKey
-}
+////////////////////////////////////////////////////////////////////////////////
+// Channel Actions                                                            //
+////////////////////////////////////////////////////////////////////////////////
 
 // DecodePublicURL decodes the channel URL into a channel pretty print. This
 // function can only be used for public channel URLs. To get the privacy level
@@ -675,65 +607,86 @@ func GetChannelInfo(_ js.Value, args []js.Value) any {
 	return utils.CopyBytesToJS(ci)
 }
 
-// JoinChannel joins the given channel. It will fail if the channel has already
-// been joined.
-//
-// Parameters:
-//   - args[0] - A portable channel string. Should be received from another user
-//     or generated via [GenerateChannel] (string).
+// GenerateChannel creates a new channel with the user as the admin and returns
+// the pretty print of the channel. This function only create a channel and does
+// not join it.
 //
-// The pretty print will be of the format:
+// The private key is saved to storage and can be accessed with
+// [ChannelsManager.ExportChannelAdminKey].
 //
-//	<Speakeasy-v3:Test_Channel|description:Channel description.|level:Public|created:1666718081766741100|secrets:+oHcqDbJPZaT3xD5NcdLY8OjOMtSQNKdKgLPmr7ugdU=|rCI0wr01dHFStjSFMvsBzFZClvDIrHLL5xbCOPaUOJ0=|493|1|7cBhJxVfQxWo+DypOISRpeWdQBhuQpAZtUbQHjBm8NQ=>
+// Parameters:
+//   - args[0] - The name of the new channel (string). The name must be between
+//     3 and 24 characters inclusive. It can only include upper and lowercase
+//     Unicode letters, digits 0 through 9, and underscores (_). It cannot be
+//     changed once a channel is created.
+//   - args[1] - The description of a channel (string). The description is
+//     optional but cannot be longer than 144 characters and can include all
+//     Unicode characters. It cannot be changed once a channel is created.
+//   - args[2] - The [broadcast.PrivacyLevel] of the channel (int). 0 = public,
+//     1 = private, and 2 = secret. Refer to the comment below for more
+//     information.
 //
 // Returns:
-//   - JSON of [bindings.ChannelInfo], which describes all relevant channel info
-//     (Uint8Array).
-//   - Throws a TypeError if joining the channel fails.
-func (ch *ChannelsManager) JoinChannel(_ js.Value, args []js.Value) any {
-	ci, err := ch.api.JoinChannel(args[0].String())
+//   - The pretty print of the channel (string).
+//   - Throws a TypeError if generating the channel fails.
+//
+// The [broadcast.PrivacyLevel] of a channel indicates the level of channel
+// information revealed when sharing it via URL. For any channel besides public
+// channels, the secret information is encrypted and a password is required to
+// share and join a channel.
+//   - A privacy level of [broadcast.Public] reveals all the information
+//     including the name, description, privacy level, public key and salt.
+//   - A privacy level of [broadcast.Private] reveals only the name and
+//     description.
+//   - A privacy level of [broadcast.Secret] reveals nothing.
+func (cm *ChannelsManager) GenerateChannel(_ js.Value, args []js.Value) any {
+	prettyPrint, err := cm.api.GenerateChannel(
+		args[0].String(), args[1].String(), args[2].Int())
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
 	}
 
-	return utils.CopyBytesToJS(ci)
+	return prettyPrint
 }
 
-// GetChannels returns the IDs of all channels that have been joined.
+// JoinChannel joins the given channel. It will return the error
+// [channels.ChannelAlreadyExistsErr] if the channel has already been joined.
 //
-// Returns:
-//   - JSON of an array of marshalled [id.ID] (Uint8Array).
-//   - Throws a TypeError if getting the channels fails.
+// Parameters:
+//   - args[0] - A portable channel string. Should be received from another user
+//     or generated via [ChannelsManager.GenerateChannel] (string).
 //
-// JSON Example:
+// The pretty print will be of the format:
 //
-//	{
-//	  "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID",
-//	  "15tNdkKbYXoMn58NO6VbDMDWFEyIhTWEGsvgcJsHWAgD"
-//	}
-func (ch *ChannelsManager) GetChannels(js.Value, []js.Value) any {
-	channelList, err := ch.api.GetChannels()
+//	<Speakeasy-v3:Test_Channel|description:Channel description.|level:Public|created:1666718081766741100|secrets:+oHcqDbJPZaT3xD5NcdLY8OjOMtSQNKdKgLPmr7ugdU=|rCI0wr01dHFStjSFMvsBzFZClvDIrHLL5xbCOPaUOJ0=|493|1|7cBhJxVfQxWo+DypOISRpeWdQBhuQpAZtUbQHjBm8NQ=>
+//
+// Returns:
+//   - JSON of [bindings.ChannelInfo], which describes all relevant channel info
+//     (Uint8Array).
+//   - Throws a TypeError if joining the channel fails.
+func (cm *ChannelsManager) JoinChannel(_ js.Value, args []js.Value) any {
+	ci, err := cm.api.JoinChannel(args[0].String())
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
 	}
 
-	return utils.CopyBytesToJS(channelList)
+	return utils.CopyBytesToJS(ci)
 }
 
-// LeaveChannel leaves the given channel. It will return an error if the channel
-// was not previously joined.
+// LeaveChannel leaves the given channel. It will return the error
+// [channels.ChannelDoesNotExistsErr] if the channel was not previously joined.
 //
 // Parameters:
 //   - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array).
 //
 // Returns:
 //   - Throws a TypeError if the channel does not exist.
-func (ch *ChannelsManager) LeaveChannel(_ js.Value, args []js.Value) any {
+func (cm *ChannelsManager) LeaveChannel(_ js.Value, args []js.Value) any {
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 
-	err := ch.api.LeaveChannel(marshalledChanId)
+	err := cm.api.LeaveChannel(marshalledChanId)
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -745,15 +698,18 @@ func (ch *ChannelsManager) LeaveChannel(_ js.Value, args []js.Value) any {
 // ReplayChannel replays all messages from the channel within the network's
 // memory (~3 weeks) over the event model.
 //
+// Returns the error [channels.ChannelDoesNotExistsErr] if the channel was not
+// previously joined.
+//
 // Parameters:
-//   - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array).
+//   - args[0] - Marshalled bytes of the channel's [id.ID] (Uint8Array).
 //
 // Returns:
 //   - Throws a TypeError if the replay fails.
-func (ch *ChannelsManager) ReplayChannel(_ js.Value, args []js.Value) any {
+func (cm *ChannelsManager) ReplayChannel(_ js.Value, args []js.Value) any {
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 
-	err := ch.api.ReplayChannel(marshalledChanId)
+	err := cm.api.ReplayChannel(marshalledChanId)
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -762,6 +718,28 @@ func (ch *ChannelsManager) ReplayChannel(_ js.Value, args []js.Value) any {
 	return nil
 }
 
+// GetChannels returns the IDs of all channels that have been joined.
+//
+// Returns:
+//   - JSON of an array of marshalled [id.ID] (Uint8Array).
+//   - Throws a TypeError if getting the channels fails.
+//
+// JSON Example:
+//
+//	{
+//	  "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID",
+//	  "15tNdkKbYXoMn58NO6VbDMDWFEyIhTWEGsvgcJsHWAgD"
+//	}
+func (cm *ChannelsManager) GetChannels(js.Value, []js.Value) any {
+	channelList, err := cm.api.GetChannels()
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+
+	return utils.CopyBytesToJS(channelList)
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Channel Share URL                                                          //
 ////////////////////////////////////////////////////////////////////////////////
@@ -786,8 +764,8 @@ type ShareURL struct {
 // channel. If it is set to 0, then it can be shared unlimited times. The max
 // uses is set as a URL parameter using the key [broadcast.MaxUsesKey]. Note
 // that this number is also encoded in the secret data for private and secret
-// URLs, so if the number is changed in the URL, is will be verified when
-// calling [DecodePublicURL] or [DecodePrivateURL]. There is no enforcement for
+// URLs, so if the number is changed in the URL, it will be verified when
+// calling [DecodePublicURL] and [DecodePrivateURL]. There is no enforcement for
 // public URLs.
 //
 // Parameters:
@@ -800,13 +778,13 @@ type ShareURL struct {
 // Returns:
 //   - JSON of [bindings.ShareURL] (Uint8Array).
 //   - Throws a TypeError if generating the URL fails.
-func (ch *ChannelsManager) GetShareURL(_ js.Value, args []js.Value) any {
+func (cm *ChannelsManager) GetShareURL(_ js.Value, args []js.Value) any {
 	cmixID := args[0].Int()
 	host := args[1].String()
 	maxUses := args[2].Int()
 	marshalledChanId := utils.CopyBytesToGo(args[3])
 
-	su, err := ch.api.GetShareURL(cmixID, host, maxUses, marshalledChanId)
+	su, err := cm.api.GetShareURL(cmixID, host, maxUses, marshalledChanId)
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -823,7 +801,7 @@ func (ch *ChannelsManager) GetShareURL(_ js.Value, args []js.Value) any {
 //
 // Returns:
 //   - An int that corresponds to the [broadcast.PrivacyLevel] as outlined
-//     below.
+//     below (int).
 //   - Throws a TypeError if parsing the URL fails.
 //
 // Possible returns:
@@ -845,84 +823,54 @@ func GetShareUrlType(_ js.Value, args []js.Value) any {
 // Channel Sending Methods and Reports                                        //
 ////////////////////////////////////////////////////////////////////////////////
 
+// ValidForever returns the value to use for validUntil when you want a message
+// to be available for the maximum amount of time.
+//
+// Returns:
+//   - The maximum amount of time (int).
+func ValidForever(js.Value, []js.Value) any {
+	return bindings.ValidForever()
+}
+
 // SendGeneric is used to send a raw message over a channel. In general, it
-// should be wrapped in a function which defines the wire protocol. If the final
-// message, before being sent over the wire, is too long, this will return an
-// error. Due to the underlying encoding using compression, it isn't possible to
-// define the largest payload that can be sent, but it will always be possible
-// to send a payload of 802 bytes at minimum. The meaning of validUntil depends
-// on the use case.
+// should be wrapped in a function that defines the wire protocol.
+//
+// If the final message, before being sent over the wire, is too long, this
+// will return an error. Due to the underlying encoding using compression,
+// it is not possible to define the largest payload that can be sent, but it
+// will always be possible to send a payload of 802 bytes at minimum.
 //
 // Parameters:
 //   - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array).
 //   - args[1] - The message type of the message. This will be a valid
 //     [channels.MessageType] (int).
 //   - args[2] - The contents of the message (Uint8Array).
-//   - args[3] - The lease of the message. This will be how long the message is
-//     valid until, in milliseconds. As per the [channels.Manager]
-//     documentation, this has different meanings depending on the use case.
-//     These use cases may be generic enough that they will not be enumerated
-//     here (int).
-//   - args[4] - JSON of [xxdk.CMIXParams]. If left empty
+//   - args[3] - The lease of the message. This will be how long the
+//     message is available from the network, in milliseconds (int). As per the
+//     [channels.Manager] documentation, this has different meanings depending
+//     on the use case. These use cases may be generic enough that they will not
+//     be enumerated here. Use [ValidForever] to last the max message life.
+//   - args[4] - Set tracked to true if the message should be tracked in the
+//     sendTracker, which allows messages to be shown locally before they are
+//     received on the network. In general, all messages that will be displayed
+//     to the user should be tracked while all actions should not be (boolean).
+//   - args[5] - JSON of [xxdk.CMIXParams]. If left empty
 //     [bindings.GetDefaultCMixParams] will be used internally (Uint8Array).
 //
 // Returns a promise:
 //   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
 //   - Rejected with an error if sending fails.
-func (ch *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any {
+func (cm *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any {
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 	messageType := args[1].Int()
 	message := utils.CopyBytesToGo(args[2])
 	leaseTimeMS := int64(args[3].Int())
-	cmixParamsJSON := utils.CopyBytesToGo(args[4])
-
-	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := ch.api.SendGeneric(
-			marshalledChanId, messageType, message, leaseTimeMS, cmixParamsJSON)
-		if err != nil {
-			reject(utils.JsTrace(err))
-		} else {
-			resolve(utils.CopyBytesToJS(sendReport))
-		}
-	}
-
-	return utils.CreatePromise(promiseFn)
-}
-
-// SendAdminGeneric is used to send a raw message over a channel encrypted with
-// admin keys, identifying it as sent by the admin. In general, it should be
-// wrapped in a function that defines the wire protocol. If the final message,
-// before being sent over the wire, is too long, this will return an error. The
-// message must be at most 510 bytes long.
-//
-// Parameters:
-//   - args[0] - The PEM-encode admin RSA private key (Uint8Array).
-//   - args[1] - Marshalled bytes of the channel [id.ID] (Uint8Array).
-//   - args[2] - The message type of the message. This will be a valid
-//     [channels.MessageType] (int).
-//   - args[3] - The contents of the message (Uint8Array).
-//   - args[4] - The lease of the message. This will be how long the message is
-//     valid until, in milliseconds. As per the [channels.Manager]
-//     documentation, this has different meanings depending on the use case.
-//     These use cases may be generic enough that they will not be enumerated
-//     here (int).
-//   - args[5] - JSON of [xxdk.CMIXParams]. If left empty
-//     [bindings.GetDefaultCMixParams] will be used internally (Uint8Array).
-//
-// Returns a promise:
-//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
-//   - Rejected with an error if sending fails.
-func (ch *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any {
-	adminPrivateKey := utils.CopyBytesToGo(args[0])
-	marshalledChanId := utils.CopyBytesToGo(args[1])
-	messageType := args[2].Int()
-	message := utils.CopyBytesToGo(args[3])
-	leaseTimeMS := int64(args[4].Int())
+	tracked := args[4].Bool()
 	cmixParamsJSON := utils.CopyBytesToGo(args[5])
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := ch.api.SendAdminGeneric(adminPrivateKey,
-			marshalledChanId, messageType, message, leaseTimeMS, cmixParamsJSON)
+		sendReport, err := cm.api.SendGeneric(marshalledChanId, messageType,
+			message, leaseTimeMS, tracked, cmixParamsJSON)
 		if err != nil {
 			reject(utils.JsTrace(err))
 		} else {
@@ -934,6 +882,7 @@ func (ch *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any {
 }
 
 // SendMessage is used to send a formatted message over a channel.
+//
 // Due to the underlying encoding using compression, it isn't possible to define
 // the largest payload that can be sent, but it will always be possible to send
 // a payload of 798 bytes at minimum.
@@ -944,25 +893,25 @@ func (ch *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any {
 // Parameters:
 //   - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array).
 //   - args[1] - The contents of the message (string).
-//   - args[2] - The lease of the message. This will be how long the message is
-//     valid until, in milliseconds. As per the [channels.Manager]
-//     documentation, this has different meanings depending on the use case.
-//     These use cases may be generic enough that they will not be enumerated
-//     here (int).
+//   - args[2] - The lease of the message. This will be how long the
+//     message is available from the network, in milliseconds (int). As per the
+//     [channels.Manager] documentation, this has different meanings depending
+//     on the use case. These use cases may be generic enough that they will not
+//     be enumerated here. Use [ValidForever] to last the max message life.
 //   - args[3] - JSON of [xxdk.CMIXParams]. If left empty
 //     [bindings.GetDefaultCMixParams] will be used internally (Uint8Array).
 //
 // Returns a promise:
 //   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
 //   - Rejected with an error if sending fails.
-func (ch *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any {
+func (cm *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any {
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 	message := args[1].String()
 	leaseTimeMS := int64(args[2].Int())
 	cmixParamsJSON := utils.CopyBytesToGo(args[3])
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := ch.api.SendMessage(
+		sendReport, err := cm.api.SendMessage(
 			marshalledChanId, message, leaseTimeMS, cmixParamsJSON)
 		if err != nil {
 			reject(utils.JsTrace(err))
@@ -974,15 +923,14 @@ func (ch *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any {
 	return utils.CreatePromise(promiseFn)
 }
 
-// SendReply is used to send a formatted message over a channel. Due to the
-// underlying encoding using compression, it isn't possible to define the
-// largest payload that can be sent, but it will always be possible to send a
-// payload of 766 bytes at minimum.
+// SendReply is used to send a formatted message over a channel.
+//
+// Due to the underlying encoding using compression, it is not possible to
+// define the largest payload that can be sent, but it will always be possible
+// to send a payload of 766 bytes at minimum.
 //
-// If the message ID the reply is sent to is nonexistent, the other side will
-// post the message as a normal message and not a reply. The message will auto
-// delete validUntil after the round it is sent in, lasting forever if
-// [channels.ValidForever] is used.
+// If the message ID that the reply is sent to does not exist, then the other
+// side will post the message as a normal message and not as a reply.
 //
 // Parameters:
 //   - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array).
@@ -994,18 +942,18 @@ func (ch *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any {
 //     your own. Alternatively, if reacting to another user's message, you may
 //     retrieve it via the [bindings.ChannelMessageReceptionCallback] registered
 //     using  RegisterReceiveHandler (Uint8Array).
-//   - args[3] - The lease of the message. This will be how long the message is
-//     valid until, in milliseconds. As per the [channels.Manager]
-//     documentation, this has different meanings depending on the use case.
-//     These use cases may be generic enough that they will not be enumerated
-//     here (int).
+//   - args[3] - The lease of the message. This will be how long the
+//     message is available from the network, in milliseconds (int). As per the
+//     [channels.Manager] documentation, this has different meanings depending
+//     on the use case. These use cases may be generic enough that they will not
+//     be enumerated here. Use [ValidForever] to last the max message life.
 //   - args[4] - JSON of [xxdk.CMIXParams]. If left empty
 //     [bindings.GetDefaultCMixParams] will be used internally (Uint8Array).
 //
 // Returns a promise:
 //   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
 //   - Rejected with an error if sending fails.
-func (ch *ChannelsManager) SendReply(_ js.Value, args []js.Value) any {
+func (cm *ChannelsManager) SendReply(_ js.Value, args []js.Value) any {
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 	message := args[1].String()
 	messageToReactTo := utils.CopyBytesToGo(args[2])
@@ -1013,7 +961,7 @@ func (ch *ChannelsManager) SendReply(_ js.Value, args []js.Value) any {
 	cmixParamsJSON := utils.CopyBytesToGo(args[4])
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := ch.api.SendReply(marshalledChanId, message,
+		sendReport, err := cm.api.SendReply(marshalledChanId, message,
 			messageToReactTo, leaseTimeMS, cmixParamsJSON)
 		if err != nil {
 			reject(utils.JsTrace(err))
@@ -1025,10 +973,11 @@ func (ch *ChannelsManager) SendReply(_ js.Value, args []js.Value) any {
 	return utils.CreatePromise(promiseFn)
 }
 
-// SendReaction is used to send a reaction to a message over a channel.
-// The reaction must be a single emoji with no other characters, and will
-// be rejected otherwise.
-// Users will drop the reaction if they do not recognize the reactTo message.
+// SendReaction is used to send a reaction to a message over a channel. The
+// reaction must be a single emoji with no other characters, and will be
+// rejected otherwise.
+//
+// Clients will drop the reaction if they do not recognize the reactTo message.
 //
 // Parameters:
 //   - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array).
@@ -1045,14 +994,14 @@ func (ch *ChannelsManager) SendReply(_ js.Value, args []js.Value) any {
 // Returns a promise:
 //   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
 //   - Rejected with an error if sending fails.
-func (ch *ChannelsManager) SendReaction(_ js.Value, args []js.Value) any {
+func (cm *ChannelsManager) SendReaction(_ js.Value, args []js.Value) any {
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 	reaction := args[1].String()
 	messageToReactTo := utils.CopyBytesToGo(args[2])
 	cmixParamsJSON := utils.CopyBytesToGo(args[3])
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := ch.api.SendReaction(
+		sendReport, err := cm.api.SendReaction(
 			marshalledChanId, reaction, messageToReactTo, cmixParamsJSON)
 		if err != nil {
 			reject(utils.JsTrace(err))
@@ -1064,14 +1013,197 @@ func (ch *ChannelsManager) SendReaction(_ js.Value, args []js.Value) any {
 	return utils.CreatePromise(promiseFn)
 }
 
-// GetIdentity returns the marshaled public identity ([channel.Identity]) that
-// the channel is using.
+////////////////////////////////////////////////////////////////////////////////
+// Admin Sending                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+// SendAdminGeneric is used to send a raw message over a channel encrypted with
+// admin keys, identifying it as sent by the admin. In general, it should be
+// wrapped in a function that defines the wire protocol.
+//
+// If the final message, before being sent over the wire, is too long, this will
+// return an error. The message must be at most 510 bytes long.
+//
+// If the user is not an admin of the channel (i.e. does not have a private key
+// for the channel saved to storage), then the error [channels.NotAnAdminErr] is
+// returned.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array).
+//   - args[1] - The message type of the message. This will be a valid
+//     [channels.MessageType] (int).
+//   - args[2] - The contents of the message (Uint8Array). The message should be
+//     at most 510 bytes.
+//   - args[3] - The lease of the message. This will be how long the
+//     message is available from the network, in milliseconds (int). As per the
+//     [channels.Manager] documentation, this has different meanings depending
+//     on the use case. These use cases may be generic enough that they will not
+//     be enumerated here. Use [ValidForever] to last the max message life.
+//   - args[4] - Set tracked to true if the message should be tracked in the
+//     sendTracker, which allows messages to be shown locally before they are
+//     received on the network. In general, all messages that will be displayed
+//     to the user should be tracked while all actions should not be (boolean).
+//   - args[5] - JSON of [xxdk.CMIXParams]. If left empty
+//     [bindings.GetDefaultCMixParams] will be used internally (Uint8Array).
+//
+// Returns a promise:
+//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
+//   - Rejected with an error if sending fails.
+func (cm *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any {
+	marshalledChanId := utils.CopyBytesToGo(args[0])
+	messageType := args[1].Int()
+	message := utils.CopyBytesToGo(args[2])
+	leaseTimeMS := int64(args[3].Int())
+	tracked := args[4].Bool()
+	cmixParamsJSON := utils.CopyBytesToGo(args[5])
+
+	promiseFn := func(resolve, reject func(args ...any) js.Value) {
+		sendReport, err := cm.api.SendAdminGeneric(marshalledChanId,
+			messageType, message, leaseTimeMS, tracked, cmixParamsJSON)
+		if err != nil {
+			reject(utils.JsTrace(err))
+		} else {
+			resolve(utils.CopyBytesToJS(sendReport))
+		}
+	}
+
+	return utils.CreatePromise(promiseFn)
+}
+
+// DeleteMessage deletes the targeted message from user's view. Users may delete
+// their own messages but only the channel admin can delete other user's
+// messages. If the user is not an admin of the channel or if they are not the
+// sender of the targetMessage, then the error [channels.NotAnAdminErr] is
+// returned.
+//
+// If undoAction is true, then the targeted message is un-deleted.
+//
+// Clients will drop the deletion if they do not recognize the target
+// message.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array).
+//   - args[1] - The marshalled [channel.MessageID] of the message you want to
+//     delete (Uint8Array).
+//   - args[2] - JSON of [xxdk.CMIXParams]. This may be empty, and
+//     [GetDefaultCMixParams] will be used internally (Uint8Array).
+//
+// Returns a promise:
+//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
+//   - Rejected with an error if sending fails.
+func (cm *ChannelsManager) DeleteMessage(_ js.Value, args []js.Value) any {
+	channelIdBytes := utils.CopyBytesToGo(args[0])
+	targetMessageIdBytes := utils.CopyBytesToGo(args[1])
+	cmixParamsJSON := utils.CopyBytesToGo(args[2])
+
+	promiseFn := func(resolve, reject func(args ...any) js.Value) {
+		sendReport, err := cm.api.DeleteMessage(
+			channelIdBytes, targetMessageIdBytes, cmixParamsJSON)
+		if err != nil {
+			reject(utils.JsTrace(err))
+		} else {
+			resolve(utils.CopyBytesToJS(sendReport))
+		}
+	}
+
+	return utils.CreatePromise(promiseFn)
+}
+
+// PinMessage pins the target message to the top of a channel view for all users
+// in the specified channel. Only the channel admin can pin user messages; if
+// the user is not an admin of the channel, then the error
+// [channels.NotAnAdminErr] is returned.
+//
+// If undoAction is true, then the targeted message is unpinned.
+//
+// Clients will drop the pin if they do not recognize the target message.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array).
+//   - args[1] - The marshalled [channel.MessageID] of the message you want to
+//     pin (Uint8Array).
+//   - args[2] - Set to true to unpin the message (boolean).
+//   - args[3] - The time, in milliseconds, that the message should be pinned
+//     (int). To remain pinned indefinitely, use [ValidForever].
+//   - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and
+//     [GetDefaultCMixParams] will be used internally (Uint8Array).
+//
+// Returns a promise:
+//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
+//   - Rejected with an error if sending fails.
+func (cm *ChannelsManager) PinMessage(_ js.Value, args []js.Value) any {
+	channelIdBytes := utils.CopyBytesToGo(args[0])
+	targetMessageIdBytes := utils.CopyBytesToGo(args[1])
+	undoAction := args[2].Bool()
+	validUntilMS := args[3].Int()
+	cmixParamsJSON := utils.CopyBytesToGo(args[4])
+
+	promiseFn := func(resolve, reject func(args ...any) js.Value) {
+		sendReport, err := cm.api.PinMessage(channelIdBytes,
+			targetMessageIdBytes, undoAction, validUntilMS, cmixParamsJSON)
+		if err != nil {
+			reject(utils.JsTrace(err))
+		} else {
+			resolve(utils.CopyBytesToJS(sendReport))
+		}
+	}
+
+	return utils.CreatePromise(promiseFn)
+}
+
+// MuteUser is used to mute a user in a channel. Muting a user will cause all
+// future messages from the user being dropped on reception. Muted users are
+// also unable to send messages. Only the channel admin can mute a user; if the
+// user is not an admin of the channel, then the error [channels.NotAnAdminErr]
+// is returned.
+//
+// If undoAction is true, then the targeted user will be unmuted.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array).
+//   - args[1] - The [ed25519.PublicKey] of the user you want to mute
+//     (Uint8Array).
+//   - args[2] - Set to true to unmute the message (boolean).
+//   - args[3] - The time, in milliseconds, that the user should be muted (int).
+//     To remain muted indefinitely, use [ValidForever].
+//   - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and
+//     [GetDefaultCMixParams] will be used internally (Uint8Array).
+//
+// Returns a promise:
+//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
+//   - Rejected with an error if sending fails.
+func (cm *ChannelsManager) MuteUser(_ js.Value, args []js.Value) any {
+	channelIdBytes := utils.CopyBytesToGo(args[0])
+	mutedUserPubKeyBytes := utils.CopyBytesToGo(args[1])
+	undoAction := args[2].Bool()
+	validUntilMS := args[3].Int()
+	cmixParamsJSON := utils.CopyBytesToGo(args[4])
+
+	promiseFn := func(resolve, reject func(args ...any) js.Value) {
+		sendReport, err := cm.api.MuteUser(channelIdBytes, mutedUserPubKeyBytes,
+			undoAction, validUntilMS, cmixParamsJSON)
+		if err != nil {
+			reject(utils.JsTrace(err))
+		} else {
+			resolve(utils.CopyBytesToJS(sendReport))
+		}
+	}
+
+	return utils.CreatePromise(promiseFn)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Other Channel Actions                                                      //
+////////////////////////////////////////////////////////////////////////////////
+
+// GetIdentity returns the public identity ([channel.Identity]) of the user
+// associated with this channel manager.
 //
 // Returns:
 //   - JSON of the [channel.Identity] (Uint8Array).
 //   - Throws TypeError if marshalling the identity fails.
-func (ch *ChannelsManager) GetIdentity(js.Value, []js.Value) any {
-	i, err := ch.api.GetIdentity()
+func (cm *ChannelsManager) GetIdentity(js.Value, []js.Value) any {
+	i, err := cm.api.GetIdentity()
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -1080,17 +1212,17 @@ func (ch *ChannelsManager) GetIdentity(js.Value, []js.Value) any {
 	return utils.CopyBytesToJS(i)
 }
 
-// ExportPrivateIdentity encrypts and exports the private identity to a portable
-// string.
+// ExportPrivateIdentity encrypts the private identity using the password and
+// exports it to a portable string.
 //
 // Parameters:
-//   - args[0] - Password to encrypt the identity with (string).
+//   - password - The password used to encrypt the private identity (string).
 //
 // Returns:
-//   - JSON of the encrypted private identity (Uint8Array).
+//   - Encrypted portable private identity (Uint8Array).
 //   - Throws TypeError if exporting the identity fails.
-func (ch *ChannelsManager) ExportPrivateIdentity(_ js.Value, args []js.Value) any {
-	i, err := ch.api.ExportPrivateIdentity(args[0].String())
+func (cm *ChannelsManager) ExportPrivateIdentity(_ js.Value, args []js.Value) any {
+	i, err := cm.api.ExportPrivateIdentity(args[0].String())
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -1099,12 +1231,13 @@ func (ch *ChannelsManager) ExportPrivateIdentity(_ js.Value, args []js.Value) an
 	return utils.CopyBytesToJS(i)
 }
 
-// GetStorageTag returns the storage tag needed to reload the manager.
+// GetStorageTag returns the tag where this manager is stored. To be used when
+// loading the manager. The storage tag is derived from the public key.
 //
 // Returns:
 //   - Storage tag (string).
-func (ch *ChannelsManager) GetStorageTag(js.Value, []js.Value) any {
-	return ch.api.GetStorageTag()
+func (cm *ChannelsManager) GetStorageTag(js.Value, []js.Value) any {
+	return cm.api.GetStorageTag()
 }
 
 // SetNickname sets the nickname for a given channel. The nickname must be valid
@@ -1117,8 +1250,8 @@ func (ch *ChannelsManager) GetStorageTag(js.Value, []js.Value) any {
 // Returns:
 //   - Throws TypeError if unmarshalling the ID fails or the nickname is
 //     invalid.
-func (ch *ChannelsManager) SetNickname(_ js.Value, args []js.Value) any {
-	err := ch.api.SetNickname(args[0].String(), utils.CopyBytesToGo(args[1]))
+func (cm *ChannelsManager) SetNickname(_ js.Value, args []js.Value) any {
+	err := cm.api.SetNickname(args[0].String(), utils.CopyBytesToGo(args[1]))
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -1127,15 +1260,16 @@ func (ch *ChannelsManager) SetNickname(_ js.Value, args []js.Value) any {
 	return nil
 }
 
-// DeleteNickname deletes the nickname for a given channel.
+// DeleteNickname removes the nickname for a given channel. The name will revert
+// back to the codename for this channel instead.
 //
 // Parameters:
 //   - args[0] - Marshalled bytes if the channel's [id.ID] (Uint8Array).
 //
 // Returns:
 //   - Throws TypeError if deleting the nickname fails.
-func (ch *ChannelsManager) DeleteNickname(_ js.Value, args []js.Value) any {
-	err := ch.api.DeleteNickname(utils.CopyBytesToGo(args[0]))
+func (cm *ChannelsManager) DeleteNickname(_ js.Value, args []js.Value) any {
+	err := cm.api.DeleteNickname(utils.CopyBytesToGo(args[0]))
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -1151,10 +1285,10 @@ func (ch *ChannelsManager) DeleteNickname(_ js.Value, args []js.Value) any {
 //   - args[0] - Marshalled bytes if the channel's [id.ID] (Uint8Array).
 //
 // Returns:
-//   - The nickname (string).
+//   - The nickname set for the channel (string).
 //   - Throws TypeError if the channel has no nickname set.
-func (ch *ChannelsManager) GetNickname(_ js.Value, args []js.Value) any {
-	nickname, err := ch.api.GetNickname(utils.CopyBytesToGo(args[0]))
+func (cm *ChannelsManager) GetNickname(_ js.Value, args []js.Value) any {
+	nickname, err := cm.api.GetNickname(utils.CopyBytesToGo(args[0]))
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -1184,6 +1318,201 @@ func IsNicknameValid(_ js.Value, args []js.Value) any {
 	return nil
 }
 
+// Muted returns true if the user is currently muted in the given channel.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes if the channel's [id.ID] (Uint8Array).
+//
+// Returns:
+//   - Returns true if the user is muted in the channel and false otherwise
+//     (boolean).
+//   - Throws a TypeError if the channel ID cannot be unmarshalled.
+func (cm *ChannelsManager) Muted(_ js.Value, args []js.Value) any {
+	channelIDBytes := utils.CopyBytesToGo(args[0])
+
+	muted, err := cm.api.Muted(channelIDBytes)
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+
+	return muted
+}
+
+// GetMutedUsers returns the list of the public keys for each muted user in
+// the channel. If there are no muted user or if the channel does not exist,
+// an empty list is returned.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes if the channel's [id.ID] (Uint8Array).
+//
+// Returns:
+//   - JSON of an array of ed25519.PublicKey (Uint8Array). Look below for an
+//     example.
+//   - Throws a TypeError if the channel ID cannot be unmarshalled.
+//
+// Example return:
+//
+//	["k2IrybDXjJtqxjS6Tx/6m3bXvT/4zFYOJnACNWTvESE=","ocELv7KyeCskLz4cm0klLWhmFLYvQL2FMDco79GTXYw=","mmxoDgoTEYwaRyEzq5Npa24IIs+3B5LXhll/8K5yCv0="]
+func (cm *ChannelsManager) GetMutedUsers(_ js.Value, args []js.Value) any {
+	channelIDBytes := utils.CopyBytesToGo(args[0])
+	mutedUsers, err := cm.api.GetMutedUsers(channelIDBytes)
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+
+	return utils.CopyBytesToJS(mutedUsers)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Admin Management                                                           //
+////////////////////////////////////////////////////////////////////////////////
+
+// IsChannelAdmin returns true if the user is an admin of the channel.
+//
+// Parameters:
+//   - args[0] - The marshalled bytes of the channel's [id.ID] (Uint8Array)
+//
+// Returns:
+//   - True if the user is an admin in the channel and false otherwise
+//     (boolean).
+//   - Throws a TypeError if the channel ID cannot be unmarshalled.
+func (cm *ChannelsManager) IsChannelAdmin(_ js.Value, args []js.Value) any {
+	isAdmin, err := cm.api.IsChannelAdmin(utils.CopyBytesToGo(args[0]))
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+
+	return isAdmin
+}
+
+// ExportChannelAdminKey gets the private key for the given channel ID, encrypts
+// it with the provided encryptionPassword, and exports it into a portable
+// format. Returns an error if the user is not an admin of the channel.
+//
+// This key can be provided to other users in a channel to grant them admin
+// access using [ChannelsManager.ImportChannelAdminKey].
+//
+// The private key is encrypted using a key generated from the password using
+// Argon2. Each call to ExportChannelAdminKey produces a different encrypted
+// packet regardless if the same password is used for the same channel. It
+// cannot be determined which channel the payload is for nor that two payloads
+// are for the same channel.
+//
+// The passwords between each call are not related. They can be the same or
+// different with no adverse impact on the security properties.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes of the channel's [id.ID] (Uint8Array).
+//   - args[1] - The password used to encrypt the private key (string). The
+//     passwords between each call are not related. They can be the same or
+//     different with no adverse impact on the security properties.
+//
+// Returns:
+//   - Portable string of the channel private key encrypted with the password
+//     (Uint8Array).
+//   - Throws a TypeError if the user is not an admin for the channel.
+func (cm *ChannelsManager) ExportChannelAdminKey(_ js.Value, args []js.Value) any {
+	pk, err := cm.api.ExportChannelAdminKey(
+		utils.CopyBytesToGo(args[0]), args[1].String())
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+	return utils.CopyBytesToJS(pk)
+}
+
+// VerifyChannelAdminKey verifies that the encrypted private key can be
+// decrypted and that it matches the expected channel. Returns false if private
+// key does not belong to the given channel.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes of the channel's [id.ID] (Uint8Array).
+//   - args[1] - The password used to encrypt the private key (string)
+//   - args[2] - The encrypted channel private key packet (Uint8Array).
+//
+// Returns:
+//   - Returns false if private key does not belong to the given channel ID
+//     (boolean).
+//   - Throws a TypeError if the password is invalid.
+//
+// Returns:
+//   - bool - True if the private key belongs to the channel and false
+//     otherwise.
+//   - Throws a TypeError with the message [channels.WrongPasswordErr] for an
+//     invalid password.
+//   - Throws a TypeError with the message [channels.ChannelDoesNotExistsErr] i
+//     the channel has not already been joined.
+func (cm *ChannelsManager) VerifyChannelAdminKey(_ js.Value, args []js.Value) any {
+	channelID := utils.CopyBytesToGo(args[0])
+	encryptionPassword := args[1].String()
+	encryptedPrivKey := utils.CopyBytesToGo(args[2])
+	valid, err := cm.api.VerifyChannelAdminKey(
+		channelID, encryptionPassword, encryptedPrivKey)
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+
+	return valid
+}
+
+// ImportChannelAdminKey decrypts and imports the given encrypted private key
+// and grants the user admin access to the channel the private key belongs to.
+// Returns an error if the private key cannot be decrypted or if the private key
+// is for the wrong channel.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes of the channel's [id.ID] (Uint8Array).
+//   - args[1] - The password used to encrypt the private key (string)
+//   - args[2] - The encrypted channel private key packet (Uint8Array).
+//
+// Returns:
+//   - Throws a TypeError if the password is invalid or the private key does
+//     not match the channel ID.
+//   - Throws a TypeError with the message [channels.WrongPasswordErr] for an
+//     invalid password.
+//   - Throws a TypeError with the message [channels.ChannelDoesNotExistsErr] if
+//     the channel has not already been joined.
+//   - Throws a TypeError with the message [channels.WrongPrivateKeyErr] if the
+//     private key does not belong to the channel.
+func (cm *ChannelsManager) ImportChannelAdminKey(_ js.Value, args []js.Value) any {
+	channelID := utils.CopyBytesToGo(args[0])
+	encryptionPassword := args[1].String()
+	encryptedPrivKey := utils.CopyBytesToGo(args[2])
+	err := cm.api.ImportChannelAdminKey(
+		channelID, encryptionPassword, encryptedPrivKey)
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+
+	return nil
+}
+
+// DeleteChannelAdminKey deletes the private key for the given channel.
+//
+// CAUTION: This will remove admin access. This cannot be undone. If the
+// private key is deleted, it cannot be recovered and the channel can never
+// have another admin.
+//
+// Parameters:
+//   - args[0] - The marshalled bytes of the channel's [id.ID] (Uint8Array)
+//
+// Returns:
+//   - Throws a TypeError if the deletion fails.
+func (cm *ChannelsManager) DeleteChannelAdminKey(_ js.Value, args []js.Value) any {
+	err := cm.api.DeleteChannelAdminKey(utils.CopyBytesToGo(args[0]))
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+
+	return nil
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Channel Receiving Logic and Callback Registration                          //
 ////////////////////////////////////////////////////////////////////////////////
@@ -1225,15 +1554,28 @@ func (cmrCB *channelMessageReceptionCallback) Callback(
 //   - args[1] - Javascript object that has functions that implement the
 //     [bindings.ChannelMessageReceptionCallback] interface. This callback will
 //     be executed when a channel message of the messageType is received.
+//   - args[2] - A name describing what type of messages the listener picks up.
+//     This is used for debugging and logging (string).
+//   - args[3] - Set to true if this listener can receive messages from normal
+//     users (boolean).
+//   - args[4] - Set to true if this listener can receive messages from admins
+//     (boolean).
+//   - args[5] - Set to true if this listener can receive messages from muted
+//     users (boolean).
 //
 // Returns:
 //   - Throws a TypeError if registering the handler fails.
-func (ch *ChannelsManager) RegisterReceiveHandler(_ js.Value, args []js.Value) any {
+func (cm *ChannelsManager) RegisterReceiveHandler(_ js.Value, args []js.Value) any {
 	messageType := args[0].Int()
 	listenerCb := &channelMessageReceptionCallback{
 		utils.WrapCB(args[1], "Callback")}
+	name := args[2].String()
+	userSpace := args[3].Bool()
+	adminSpace := args[4].Bool()
+	mutedSpace := args[5].Bool()
 
-	err := ch.api.RegisterReceiveHandler(messageType, listenerCb)
+	err := cm.api.RegisterReceiveHandler(
+		messageType, listenerCb, name, userSpace, adminSpace, mutedSpace)
 	if err != nil {
 		utils.Throw(utils.TypeError, err)
 		return nil
@@ -1246,15 +1588,41 @@ func (ch *ChannelsManager) RegisterReceiveHandler(_ js.Value, args []js.Value) a
 // Event Model Logic                                                          //
 ////////////////////////////////////////////////////////////////////////////////
 
+// eventModelBuilder adheres to the [bindings.EventModelBuilder] interface.
+type eventModelBuilder struct {
+	build func(args ...any) js.Value
+}
+
+// Build initializes and returns the event model.  It wraps a Javascript object
+// that has all the methods in [bindings.EventModel] to make it adhere to the Go
+// interface [bindings.EventModel].
+func (emb *eventModelBuilder) Build(path string) bindings.EventModel {
+	emJs := emb.build(path)
+	return &eventModel{
+		joinChannel:         utils.WrapCB(emJs, "JoinChannel"),
+		leaveChannel:        utils.WrapCB(emJs, "LeaveChannel"),
+		receiveMessage:      utils.WrapCB(emJs, "ReceiveMessage"),
+		receiveReply:        utils.WrapCB(emJs, "ReceiveReply"),
+		receiveReaction:     utils.WrapCB(emJs, "ReceiveReaction"),
+		updateFromUUID:      utils.WrapCB(emJs, "UpdateFromUUID"),
+		updateFromMessageID: utils.WrapCB(emJs, "UpdateFromMessageID"),
+		getMessage:          utils.WrapCB(emJs, "GetMessage"),
+		deleteMessage:       utils.WrapCB(emJs, "DeleteMessage"),
+	}
+}
+
 // eventModel wraps Javascript callbacks to adhere to the [bindings.EventModel]
 // interface.
 type eventModel struct {
-	joinChannel      func(args ...any) js.Value
-	leaveChannel     func(args ...any) js.Value
-	receiveMessage   func(args ...any) js.Value
-	receiveReply     func(args ...any) js.Value
-	receiveReaction  func(args ...any) js.Value
-	updateSentStatus func(args ...any) js.Value
+	joinChannel         func(args ...any) js.Value
+	leaveChannel        func(args ...any) js.Value
+	receiveMessage      func(args ...any) js.Value
+	receiveReply        func(args ...any) js.Value
+	receiveReaction     func(args ...any) js.Value
+	updateFromUUID      func(args ...any) js.Value
+	updateFromMessageID func(args ...any) js.Value
+	getMessage          func(args ...any) js.Value
+	deleteMessage       func(args ...any) js.Value
 }
 
 // JoinChannel is called whenever a channel is joined locally.
@@ -1304,11 +1672,11 @@ func (em *eventModel) LeaveChannel(channelID []byte) {
 //     later with [eventModel.UpdateSentStatus].
 func (em *eventModel) ReceiveMessage(channelID, messageID []byte, nickname,
 	text string, pubKey []byte, dmToken int32, codeset int, timestamp, lease, roundId, msgType,
-	status int64) int64 {
+	status int64, hidden bool) int64 {
 	uuid := em.receiveMessage(utils.CopyBytesToJS(channelID),
 		utils.CopyBytesToJS(messageID), nickname, text,
 		utils.CopyBytesToJS(pubKey), dmToken, codeset, timestamp, lease, roundId,
-		msgType, status)
+		msgType, status, hidden)
 
 	return int64(uuid.Int())
 }
@@ -1349,11 +1717,11 @@ func (em *eventModel) ReceiveMessage(channelID, messageID []byte, nickname,
 //     later with [eventModel.UpdateSentStatus].
 func (em *eventModel) ReceiveReply(channelID, messageID, reactionTo []byte,
 	senderUsername, text string, pubKey []byte, dmToken int32, codeset int, timestamp, lease,
-	roundId, msgType, status int64) int64 {
+	roundId, msgType, status int64, hidden bool) int64 {
 	uuid := em.receiveReply(utils.CopyBytesToJS(channelID),
 		utils.CopyBytesToJS(messageID), utils.CopyBytesToJS(reactionTo),
 		senderUsername, text, utils.CopyBytesToJS(pubKey), dmToken, codeset,
-		timestamp, lease, roundId, msgType, status)
+		timestamp, lease, roundId, msgType, status, hidden)
 
 	return int64(uuid.Int())
 }
@@ -1394,36 +1762,118 @@ func (em *eventModel) ReceiveReply(channelID, messageID, reactionTo []byte,
 //     later with [eventModel.UpdateSentStatus].
 func (em *eventModel) ReceiveReaction(channelID, messageID, reactionTo []byte,
 	senderUsername, reaction string, pubKey []byte, dmToken int32, codeset int, timestamp,
-	lease, roundId, msgType, status int64) int64 {
+	lease, roundId, msgType, status int64, hidden bool) int64 {
 	uuid := em.receiveReaction(utils.CopyBytesToJS(channelID),
 		utils.CopyBytesToJS(messageID), utils.CopyBytesToJS(reactionTo),
 		senderUsername, reaction, utils.CopyBytesToJS(pubKey), dmToken, codeset,
-		timestamp, lease, roundId, msgType, status)
+		timestamp, lease, roundId, msgType, status, hidden)
 
 	return int64(uuid.Int())
 }
 
-// UpdateSentStatus is called whenever the sent status of a message has
-// changed.
+// UpdateFromUUID is called whenever a message at the UUID is modified.
+//
+// Parameters:
+//   - uuid - The unique identifier of the message in the database (int).
+//   - messageUpdateInfoJSON - JSON of [bindings.MessageUpdateInfo]
+//     (Uint8Array).
+func (em *eventModel) UpdateFromUUID(uuid int64, messageUpdateInfoJSON []byte) {
+	em.updateFromUUID(uuid, utils.CopyBytesToJS(messageUpdateInfoJSON))
+}
+
+// UpdateFromMessageID is called whenever a message with the message ID is
+// modified.
 //
 // Parameters:
-//   - uuid - The unique identifier for the message (int).
 //   - messageID - The bytes of the [channel.MessageID] of the received message
 //     (Uint8Array).
-//   - timestamp - Time the message was received; represented as nanoseconds
-//     since unix epoch (int).
-//   - roundId - The ID of the round that the message was received on (int).
-//   - status - The [channels.SentStatus] of the message (int).
+//   - messageUpdateInfoJSON - JSON of [bindings.MessageUpdateInfo
+//     (Uint8Array).
 //
-// Statuses will be enumerated as such:
+// Returns:
+//   - A non-negative unique uuid for the modified message by which it can be
+//     referenced later with [EventModel.UpdateFromUUID] int).
+func (em *eventModel) UpdateFromMessageID(
+	messageID []byte, messageUpdateInfoJSON []byte) int64 {
+	return int64(em.updateFromMessageID(utils.CopyBytesToJS(messageID),
+		utils.CopyBytesToJS(messageUpdateInfoJSON)).Int())
+}
+
+// GetMessage returns the message with the given [channel.MessageID].
 //
-//	Sent      =  0
-//	Delivered =  1
-//	Failed    =  2
-func (em *eventModel) UpdateSentStatus(
-	uuid int64, messageID []byte, timestamp, roundID, status int64) {
-	em.updateSentStatus(
-		uuid, utils.CopyBytesToJS(messageID), timestamp, roundID, status)
+// Note for developers: The internal Javascript function must return JSON of
+// MessageAndError, which includes the returned [channels.ModelMessage] or any
+// error that occurs during lookup.
+//
+// Parameters:
+//   - messageID - The bytes of the [channel.MessageID] of the message
+//     (Uint8Array).
+//
+// Returns:
+//   - JSON of [channels.ModelMessage] (Uint8Array).
+func (em *eventModel) GetMessage(messageID []byte) ([]byte, error) {
+	messageAndErrorBytes :=
+		utils.CopyBytesToGo(em.getMessage(utils.CopyBytesToJS(messageID)))
+
+	var mae MessageAndError
+	err := json.Unmarshal(messageAndErrorBytes, &mae)
+	if err != nil {
+		return nil, err
+	}
+
+	if mae.Error != "" {
+		return nil, errors.New(mae.Error)
+	}
+
+	return json.Marshal(mae.ModelMessage)
+}
+
+// DeleteMessage deletes the message with the given [channel.MessageID] from
+// the database.
+//
+// Parameters:
+//  - messageID - The bytes of the [channel.MessageID] of the message.
+func (em *eventModel) DeleteMessage(messageID []byte) error {
+	err := em.deleteMessage(utils.CopyBytesToJS(messageID))
+	if !err.IsUndefined() {
+		return js.Error{Value: err}
+	}
+
+	return nil
+}
+
+// MessageAndError contains a message returned by eventModel.GetMessage or any
+// possible error that occurs during lookup. Only one field should be present at
+// a time; if an error occurs, ModelMessage should be empty.
+//
+// Example JSON:
+//
+//	{
+//	  "ModelMessage": {
+//	    "UUID": 50,
+//	    "Nickname": "Nickname",
+//	    "MessageID": "ODg5goFIBvpvqPzuoYGqmvxFYBgj0MMiQxAB51Q2nPs=",
+//	    "ChannelID": "R+xKJTH6m4YRS4f0JggK3fTu10sANmtahS0Qtc8yi/AD",
+//	    "ParentMessageID": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
+//	    "Timestamp": "1955-11-05T12:01:00-07:00",
+//	    "Lease": 21600000000000,
+//	    "Status": 2,
+//	    "Hidden": false,
+//	    "Pinned": false,
+//	    "Content": "VGhpcyBpcyBzb21lIG1lc3NhZ2UgY29udGVudC4=",
+//	    "Type": 1,
+//	    "Round": 7,
+//	    "PubKey": "QyTtpndOf3sDZehVpOBQzQNBe1R2Eae7qlAEDZJ2mLg=",
+//	    "CodesetVersion": 0
+//	  },
+//	  "Error": ""
+//	}
+type MessageAndError struct {
+	// MessageJSON should contain the JSON of channels.ModelMessage.
+	ModelMessage channels.ModelMessage
+
+	// Error should only be filled when an error occurs on message lookup.
+	Error string
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1545,8 +1995,7 @@ func (c *ChannelDbCipher) MarshalJSON(js.Value, []js.Value) any {
 	return utils.CopyBytesToJS(data)
 }
 
-// UnmarshalJSON unmarshalls JSON into the cipher. This function adheres to the
-// json.Unmarshaler interface.
+// UnmarshalJSON unmarshalls JSON into the cipher.
 //
 // Note that this function does not transfer the internal RNG. Use
 // [channel.NewCipherFromJSON] to properly reconstruct a cipher from JSON.
diff --git a/wasm/connect.go b/wasm/connect.go
index 5d8e347dbb34c9adf4f724eee13a3eda43fc4f57..bfb95a6d882f808277a856dfbda9937c3bb3d687 100644
--- a/wasm/connect.go
+++ b/wasm/connect.go
@@ -80,10 +80,6 @@ func (c *Cmix) Connect(_ js.Value, args []js.Value) any {
 // SendE2E is a wrapper for sending specifically to the [Connection]'s
 // [partner.Manager].
 //
-// Returns:
-//   - []byte - the JSON marshalled bytes of the E2ESendReport object, which can
-//     be passed into [Cmix.WaitForRoundResult] to see if the send succeeded.
-//
 // Parameters:
 //   - args[0] - Message type from [catalog.MessageType] (int).
 //   - args[1] - Message payload (Uint8Array).
diff --git a/wasm/docs.go b/wasm/docs.go
index 2f783b6374afb19e8e7aede6e732274c7e17b854..b2d6f4894014b15873b2649118e2af09a8cd7091 100644
--- a/wasm/docs.go
+++ b/wasm/docs.go
@@ -10,6 +10,7 @@
 package wasm
 
 import (
+	"crypto/ed25519"
 	"github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/v4/auth"
 	"gitlab.com/elixxir/client/v4/catalog"
@@ -67,4 +68,5 @@ var (
 	_ = broadcast.PrivacyLevel(0)
 	_ = broadcast.Channel{}
 	_ = netTime.Now
+	_ = ed25519.PublicKey{}
 )