diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7ab520cd02563b548eabe925202ef87324725e2c..385f857c9c947089bf9018aabca620a02a9727c1 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -38,7 +38,6 @@ wasm-test:
     - tags
   script:
     - export PATH=/root/go/bin:$PATH
-    - echo > utils/utils_js.s
     - go mod vendor
     - unset SSH_PRIVATE_KEY
     - unset $(env | grep '=' | awk -F= '{print $1}' | grep -v PATH | grep -v GO | grep -v HOME)
diff --git a/Makefile b/Makefile
index f8c143a6a24f68f6b70d2bc64cc6028b56f4c9af..79fb0fa7dde5dfacb1a40f1e7a6cae5409447b5a 100644
--- a/Makefile
+++ b/Makefile
@@ -35,10 +35,7 @@ worker_binaries:
 binaries: binary worker_binaries
 
 wasm_tests:
-	cp utils/utils_js.s utils/utils_js.s.bak
-	> utils/utils_js.s
-	-GOOS=js GOARCH=wasm go test -v ./...
-	mv utils/utils_js.s.bak utils/utils_js.s
+	GOOS=js GOARCH=wasm go test -v ./...
 
 go_tests:
 	go test ./... -v
diff --git a/go.mod b/go.mod
index b41a262ff540e218f685e01353622c2db8d45d38..70cf817c85d5290e76b76c9c608568e16a3364c5 100644
--- a/go.mod
+++ b/go.mod
@@ -6,10 +6,12 @@ require (
 	github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
 	github.com/hack-pad/go-indexeddb v0.2.0
 	github.com/pkg/errors v0.9.1
+	github.com/spf13/cobra v1.7.0
 	github.com/spf13/jwalterweatherman v1.1.0
 	gitlab.com/elixxir/client/v4 v4.6.3
 	gitlab.com/elixxir/crypto v0.0.7-0.20230413162806-a99ec4bfea32
 	gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c
+	gitlab.com/elixxir/wasm-utils v0.0.0-20230517220713-7418aa4da283
 	gitlab.com/xx_network/crypto v0.0.5-0.20230214003943-8a09396e95dd
 	gitlab.com/xx_network/primitives v0.0.4-0.20230310205521-c440e68e34c4
 	golang.org/x/crypto v0.5.0
@@ -24,12 +26,10 @@ require (
 	github.com/cloudflare/circl v1.2.0 // indirect
 	github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
 	github.com/elliotchance/orderedmap v1.4.0 // indirect
-	github.com/fsnotify/fsnotify v1.5.4 // indirect
 	github.com/gobwas/ws v1.1.0 // indirect
 	github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/gorilla/websocket v1.5.0 // indirect
-	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/improbable-eng/grpc-web v0.15.0 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
@@ -37,27 +37,17 @@ require (
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/klauspost/compress v1.15.9 // indirect
 	github.com/klauspost/cpuid/v2 v2.1.0 // indirect
-	github.com/magiconair/properties v1.8.6 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect
 	github.com/mattn/go-sqlite3 v1.14.15 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
-	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
 	github.com/oasisprotocol/curve25519-voi v0.0.0-20221003100820-41fad3beba17 // indirect
 	github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
-	github.com/pelletier/go-toml v1.9.5 // indirect
-	github.com/pelletier/go-toml/v2 v2.0.2 // indirect
-	github.com/pkg/profile v1.6.0 // indirect
 	github.com/rs/cors v1.8.2 // indirect
 	github.com/sethvargo/go-diceware v0.3.0 // indirect
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
 	github.com/soheilhy/cmux v0.1.5 // indirect
-	github.com/spf13/afero v1.9.2 // indirect
-	github.com/spf13/cast v1.5.0 // indirect
-	github.com/spf13/cobra v1.7.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
-	github.com/spf13/viper v1.12.0 // indirect
-	github.com/subosito/gotenv v1.4.0 // indirect
 	github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect
 	github.com/ttacon/libphonenumber v1.2.1 // indirect
 	github.com/tyler-smith/go-bip39 v1.1.0 // indirect
@@ -78,9 +68,6 @@ require (
 	google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect
 	google.golang.org/grpc v1.49.0 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
-	gopkg.in/ini.v1 v1.66.6 // indirect
-	gopkg.in/yaml.v2 v2.4.0 // indirect
-	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gorm.io/driver/sqlite v1.4.4 // indirect
 	gorm.io/gorm v1.24.3 // indirect
 	nhooyr.io/websocket v1.8.7 // indirect
diff --git a/go.sum b/go.sum
index 75aad62399baf6290ffb2634114aa930ac1ffd3a..5d4dca7bc79c10f0e5de62f01e2ccff68fd2ca29 100644
--- a/go.sum
+++ b/go.sum
@@ -1,40 +1,5 @@
 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=
@@ -79,16 +44,11 @@ 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=
@@ -114,22 +74,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=
@@ -164,20 +118,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=
@@ -197,33 +142,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=
@@ -254,19 +178,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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
@@ -286,8 +205,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=
@@ -302,7 +219,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=
@@ -315,8 +231,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=
@@ -337,8 +251,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=
@@ -381,10 +293,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=
@@ -393,9 +301,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=
@@ -447,13 +352,7 @@ 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/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
 github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
 github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
@@ -461,8 +360,6 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
 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=
@@ -473,16 +370,12 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
 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/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-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=
@@ -497,10 +390,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=
@@ -509,10 +398,6 @@ 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-20230315224936-a4459418f300 h1:oF3Pkf5NBb48KB89Q4sQXKQCIsWp1IVsqKWHWFsfBRc=
 gitlab.com/elixxir/bloomfilter v0.0.0-20230315224936-a4459418f300/go.mod h1:1X8gRIAPDisS3W6Vtr/ymiUmZMJUIwDV1o5DEOo/pzw=
-gitlab.com/elixxir/client/v4 v4.6.2-0.20230413171204-002612660098 h1:bdwXgEa0i9KpLiKQdhv6MEWAYLt3MsbNuIzFanVpWLY=
-gitlab.com/elixxir/client/v4 v4.6.2-0.20230413171204-002612660098/go.mod h1:G+lN+LvQPGcm5BQnrhnqT1xiRIAzH3OffAM+5oI9SUg=
-gitlab.com/elixxir/client/v4 v4.6.2-0.20230425190953-cd51598e9245 h1:pBwoSYD+BFIr5Wyc+PQhqm+fZGsRSNXCpF0z1cQQzK8=
-gitlab.com/elixxir/client/v4 v4.6.2-0.20230425190953-cd51598e9245/go.mod h1:G+lN+LvQPGcm5BQnrhnqT1xiRIAzH3OffAM+5oI9SUg=
 gitlab.com/elixxir/client/v4 v4.6.3 h1:oUsm5cn2Vnfqz+xwGYKrqFkPNN3sDAyp00EPGhUIA5E=
 gitlab.com/elixxir/client/v4 v4.6.3/go.mod h1:G+lN+LvQPGcm5BQnrhnqT1xiRIAzH3OffAM+5oI9SUg=
 gitlab.com/elixxir/comms v0.0.4-0.20230310205528-f06faa0d2f0b h1:8AVK93UEs/aufoqtFgyMVt9gf0oJ8F4pA60ZvEVvG+s=
@@ -523,6 +408,8 @@ 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.20230214180039-9a25e2d3969c h1:muG8ff95woeVVwQoJHCEclxBFB22lc7EixPylEkYDRU=
 gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c/go.mod h1:phun4PLkHJA6wcL4JIhhxZztrmCyJHWPNppBP3DUD2Y=
+gitlab.com/elixxir/wasm-utils v0.0.0-20230517220713-7418aa4da283 h1:6hcMS/cVSfx8z8NYvGk4p3VakZutfcSxWnP/hz3owTQ=
+gitlab.com/elixxir/wasm-utils v0.0.0-20230517220713-7418aa4da283/go.mod h1:wB7Vh/7LWUm8wYRBSd+6lxfpk4CnDaHTkLCIVKfL2TA=
 gitlab.com/xx_network/comms v0.0.4-0.20230214180029-5387fb85736d h1:AZf2h0fxyO1KxhZPP9//jG3Swb2BcuKbxtNXJgooLss=
 gitlab.com/xx_network/comms v0.0.4-0.20230214180029-5387fb85736d/go.mod h1:8cwPyH6G8C4qf/U5KDghn1ksOh79MrNqthjKDrfvbXY=
 gitlab.com/xx_network/crypto v0.0.5-0.20230214003943-8a09396e95dd h1:IleH6U5D/c2zF6YL/z3cBKqBPnI5ApNMCtU7ia4t228=
@@ -541,12 +428,7 @@ 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=
@@ -564,12 +446,9 @@ 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=
@@ -577,14 +456,6 @@ golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
 golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
 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=
@@ -592,23 +463,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=
@@ -621,58 +480,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.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
 golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
 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=
@@ -686,69 +512,40 @@ 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-20201207223542-d4d67f95c62d/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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
 golang.org/x/sys v0.4.0/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.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
 golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
@@ -756,124 +553,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=
@@ -881,23 +584,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=
@@ -922,8 +616,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=
@@ -935,7 +627,6 @@ 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=
@@ -947,18 +638,11 @@ gorm.io/gorm v1.24.3 h1:WL2ifUmzR/SLp85CSURAfybcHnGZ+yLSGSxgYXlFBHg=
 gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
 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/impl/channels/fileTransferImpl.go b/indexedDb/impl/channels/fileTransferImpl.go
index d75dc78b6dddd5825d7c1b157dddadd75d62698d..4e30a7f91933d7cae8bc76a0efd06000be5dc3ef 100644
--- a/indexedDb/impl/channels/fileTransferImpl.go
+++ b/indexedDb/impl/channels/fileTransferImpl.go
@@ -15,8 +15,8 @@ import (
 	"gitlab.com/elixxir/client/v4/channels"
 	cft "gitlab.com/elixxir/client/v4/channelsFileTransfer"
 	"gitlab.com/elixxir/crypto/fileTransfer"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
 	"strings"
 	"time"
 )
diff --git a/indexedDb/impl/channels/implementation.go b/indexedDb/impl/channels/implementation.go
index 0976d263b00011b7ec4a6a5d6bfce38c2780beb0..4d4b97cfc4daf7a1e76f90938a4425684c2456f3 100644
--- a/indexedDb/impl/channels/implementation.go
+++ b/indexedDb/impl/channels/implementation.go
@@ -26,9 +26,9 @@ import (
 	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
 	cryptoChannel "gitlab.com/elixxir/crypto/channel"
 	"gitlab.com/elixxir/crypto/message"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
 	wChannels "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/indexedDb/impl/channels/implementation_test.go b/indexedDb/impl/channels/implementation_test.go
index 4b22b8300f5549a5dc2f3902f7ed95277777555f..376ba3bc882418f2ff6fdfa6306b4896635d87a9 100644
--- a/indexedDb/impl/channels/implementation_test.go
+++ b/indexedDb/impl/channels/implementation_test.go
@@ -30,8 +30,8 @@ import (
 	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
 	cryptoChannel "gitlab.com/elixxir/crypto/channel"
 	"gitlab.com/elixxir/crypto/message"
+	"gitlab.com/elixxir/wasm-utils/storage"
 	"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
-	"gitlab.com/elixxir/xxdk-wasm/storage"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
diff --git a/indexedDb/impl/dm/implementation.go b/indexedDb/impl/dm/implementation.go
index 1c8e18050d8c36c32ede354f9afaa9a6af1993db..227e96064f2fd7b48f9470f3a2c290d2f5e8e2ae 100644
--- a/indexedDb/impl/dm/implementation.go
+++ b/indexedDb/impl/dm/implementation.go
@@ -25,8 +25,8 @@ import (
 	"gitlab.com/elixxir/client/v4/dm"
 	cryptoChannel "gitlab.com/elixxir/crypto/channel"
 	"gitlab.com/elixxir/crypto/message"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
 	"gitlab.com/xx_network/primitives/id"
 )
 
diff --git a/indexedDb/impl/dm/implementation_test.go b/indexedDb/impl/dm/implementation_test.go
index 8e05e6af5fff85af79ea0f15be9dc1e2f5a77c12..bbd10cad99115fdc2f48fca5faf678de8f012d89 100644
--- a/indexedDb/impl/dm/implementation_test.go
+++ b/indexedDb/impl/dm/implementation_test.go
@@ -17,8 +17,8 @@ import (
 	"gitlab.com/elixxir/client/v4/cmix/rounds"
 	"gitlab.com/elixxir/client/v4/dm"
 	"gitlab.com/elixxir/crypto/message"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/elixxir/xxdk-wasm/indexedDb/impl"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
 	"gitlab.com/xx_network/primitives/id"
 	"os"
 	"syscall/js"
diff --git a/indexedDb/impl/utils.go b/indexedDb/impl/utils.go
index b657240b7e7018a031365ffc8514c3fe54141471..7dbf631c9deee97f3ef79b731832aab142820fbc 100644
--- a/indexedDb/impl/utils.go
+++ b/indexedDb/impl/utils.go
@@ -18,7 +18,7 @@ import (
 	"github.com/hack-pad/go-indexeddb/idb"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 	"time"
 )
diff --git a/logging/logger.go b/logging/logger.go
index 3064a00d551a464a486c8f8a23925cf74cea7998..8155210daf6b0b81667334d8675f63bd6b2aaca5 100644
--- a/logging/logger.go
+++ b/logging/logger.go
@@ -15,7 +15,7 @@ import (
 
 	jww "github.com/spf13/jwalterweatherman"
 
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/elixxir/xxdk-wasm/worker"
 )
 
diff --git a/main.go b/main.go
index 46cdc133897c1225c9956ea44c5cc2d3018b70aa..0ec013a14e57f0da089a09976215069b4ce73485 100644
--- a/main.go
+++ b/main.go
@@ -17,9 +17,9 @@ import (
 
 	jww "github.com/spf13/jwalterweatherman"
 
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/elixxir/xxdk-wasm/logging"
 	"gitlab.com/elixxir/xxdk-wasm/storage"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
 	"gitlab.com/elixxir/xxdk-wasm/wasm"
 )
 
@@ -252,7 +252,7 @@ func setGlobals() {
 
 var (
 	logLevel, fileLogLevel      jww.Threshold
-	maxLogFileSizeMB              int
+	maxLogFileSizeMB            int
 	workerScriptURL, workerName string
 )
 
diff --git a/storage/indexedDbEncryptionTrack.go b/storage/indexedDbEncryptionTrack.go
index d568a63787490ea0979a189191272da70d957e05..bb3f049b8adeef1e2f69b535e79285338f5107bc 100644
--- a/storage/indexedDbEncryptionTrack.go
+++ b/storage/indexedDbEncryptionTrack.go
@@ -12,6 +12,8 @@ package storage
 import (
 	"github.com/pkg/errors"
 	"os"
+
+	"gitlab.com/elixxir/wasm-utils/storage"
 )
 
 // Key to store if the database is encrypted or not
@@ -22,12 +24,15 @@ const databaseEncryptionToggleKey = "xxdkWasmDatabaseEncryptionToggle/"
 func StoreIndexedDbEncryptionStatus(
 	databaseName string, encryptionStatus bool) (
 	loadedEncryptionStatus bool, err error) {
-	data, err := GetLocalStorage().GetItem(
-		databaseEncryptionToggleKey + databaseName)
+	ls := storage.GetLocalStorage()
+	data, err := ls.Get(databaseEncryptionToggleKey + databaseName)
 	if err != nil {
 		if errors.Is(err, os.ErrNotExist) {
-			GetLocalStorage().SetItem(
-				databaseEncryptionToggleKey+databaseName, []byte{1})
+			keyName := databaseEncryptionToggleKey + databaseName
+			if err = ls.Set(keyName, []byte{1}); err != nil {
+				return false,
+					errors.Wrapf(err, "localStorage: failed to set %q", keyName)
+			}
 			return encryptionStatus, nil
 		} else {
 			return false, err
diff --git a/storage/indexedDbList.go b/storage/indexedDbList.go
index a736984f0ef742d96e7a63238ea6ebfbdc25d9f9..8917fcdbf3c413d306bd6cc0687d2af80b441992 100644
--- a/storage/indexedDbList.go
+++ b/storage/indexedDbList.go
@@ -11,8 +11,11 @@ package storage
 
 import (
 	"encoding/json"
-	"github.com/pkg/errors"
 	"os"
+
+	"github.com/pkg/errors"
+
+	"gitlab.com/elixxir/wasm-utils/storage"
 )
 
 const indexedDbListKey = "xxDkWasmIndexedDbList"
@@ -20,7 +23,7 @@ const indexedDbListKey = "xxDkWasmIndexedDbList"
 // GetIndexedDbList returns the list of stored indexedDb databases.
 func GetIndexedDbList() (map[string]struct{}, error) {
 	list := make(map[string]struct{})
-	listBytes, err := GetLocalStorage().GetItem(indexedDbListKey)
+	listBytes, err := storage.GetLocalStorage().Get(indexedDbListKey)
 	if err != nil && !errors.Is(err, os.ErrNotExist) {
 		return nil, err
 	} else if err == nil {
@@ -47,7 +50,11 @@ func StoreIndexedDb(databaseName string) error {
 		return err
 	}
 
-	GetLocalStorage().SetItem(indexedDbListKey, listBytes)
+	err = storage.GetLocalStorage().Set(indexedDbListKey, listBytes)
+	if err != nil {
+		return errors.Wrapf(err,
+			"localStorage: failed to set %q", indexedDbListKey)
+	}
 
 	return nil
 }
diff --git a/storage/localStorage.go b/storage/localStorage.go
deleted file mode 100644
index d54039c99c427640b3298c7aeb87dfb819d046be..0000000000000000000000000000000000000000
--- a/storage/localStorage.go
+++ /dev/null
@@ -1,209 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package storage
-
-import (
-	"encoding/base64"
-	"encoding/json"
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
-	"os"
-	"strings"
-	"syscall/js"
-)
-
-// localStorageWasmPrefix is prefixed to every keyName saved to local storage by
-// LocalStorage. It allows the identifications and deletion of keys only created
-// by this WASM binary while ignoring keys made by other scripts on the same
-// page.
-const localStorageWasmPrefix = "xxdkWasmStorage/"
-
-// LocalStorage contains the js.Value representation of localStorage.
-type LocalStorage struct {
-	// The Javascript value containing the localStorage object
-	v js.Value
-
-	// The prefix appended to each key name. This is so that all keys created by
-	// this structure can be deleted without affecting other keys in local
-	// storage.
-	prefix string
-}
-
-// jsStorage is the global that stores Javascript as window.localStorage.
-//
-//   - Specification:
-//     https://html.spec.whatwg.org/multipage/webstorage.html#dom-localstorage-dev
-//   - Documentation:
-//     https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
-var jsStorage = newLocalStorage(localStorageWasmPrefix)
-
-// newLocalStorage creates a new LocalStorage object with the specified prefix.
-func newLocalStorage(prefix string) *LocalStorage {
-	return &LocalStorage{
-		v:      js.Global().Get("localStorage"),
-		prefix: prefix,
-	}
-}
-
-// GetLocalStorage returns Javascript's local storage.
-func GetLocalStorage() *LocalStorage {
-	return jsStorage
-}
-
-// GetItem returns a key's value from the local storage given its name. Returns
-// os.ErrNotExist if the key does not exist. Underneath, it calls
-// localStorage.GetItem().
-//
-//   - Specification:
-//     https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-getitem-dev
-//   - Documentation:
-//     https://developer.mozilla.org/en-US/docs/Web/API/Storage/getItem
-func (ls *LocalStorage) GetItem(keyName string) ([]byte, error) {
-	keyValue := ls.getItem(ls.prefix + keyName)
-	if keyValue.IsNull() {
-		return nil, os.ErrNotExist
-	}
-
-	decodedKeyValue, err := base64.StdEncoding.DecodeString(keyValue.String())
-	if err != nil {
-		return nil, err
-	}
-
-	return decodedKeyValue, nil
-}
-
-// SetItem adds a key's value to local storage given its name. Underneath, it
-// calls localStorage.SetItem().
-//
-//   - Specification:
-//     https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-setitem-dev
-//   - Documentation:
-//     https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem
-func (ls *LocalStorage) SetItem(keyName string, keyValue []byte) {
-	encodedKeyValue := base64.StdEncoding.EncodeToString(keyValue)
-	ls.setItem(ls.prefix+keyName, encodedKeyValue)
-}
-
-// RemoveItem removes a key's value from local storage given its name. If there
-// is no item with the given key, this function does nothing. Underneath, it
-// calls localStorage.RemoveItem().
-//
-//   - Specification:
-//     https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-removeitem-dev
-//   - Documentation:
-//     https://developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem
-func (ls *LocalStorage) RemoveItem(keyName string) {
-	ls.removeItem(ls.prefix + keyName)
-}
-
-// Clear clears all the keys in storage. Underneath, it calls
-// localStorage.clear().
-//
-//   - Specification:
-//     https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-clear-dev
-//   - Documentation:
-//     https://developer.mozilla.org/en-US/docs/Web/API/Storage/clear
-func (ls *LocalStorage) Clear() {
-	ls.clear()
-}
-
-// ClearPrefix clears all keys with the given prefix.  Returns the number of
-// keys cleared.
-func (ls *LocalStorage) ClearPrefix(prefix string) int {
-	// Get a copy of all key names at once
-	keys := ls.keys()
-
-	// Loop through each key
-	var n int
-	for i := 0; i < keys.Length(); i++ {
-		if v := keys.Index(i); !v.IsNull() {
-			keyName := strings.TrimPrefix(v.String(), ls.prefix)
-			if strings.HasPrefix(keyName, prefix) {
-				ls.removeItem(v.String())
-				n++
-			}
-		}
-	}
-
-	return n
-}
-
-// ClearWASM clears all the keys in storage created by WASM. Returns the number
-// of keys cleared.
-func (ls *LocalStorage) ClearWASM() int {
-	// Get a copy of all key names at once
-	keys := ls.keys()
-
-	// Loop through each key
-	var n int
-	for i := 0; i < keys.Length(); i++ {
-		if v := keys.Index(i); !v.IsNull() {
-			keyName := v.String()
-			if strings.HasPrefix(keyName, ls.prefix) {
-				ls.RemoveItem(strings.TrimPrefix(keyName, ls.prefix))
-				n++
-			}
-		}
-	}
-
-	return n
-}
-
-// Key returns the name of the nth key in localStorage. Return os.ErrNotExist if
-// the key does not exist. The order of keys is not defined. If there is no item
-// with the given key, this function does nothing. Underneath, it calls
-// localStorage.key().
-//
-//   - Specification:
-//     https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-key-dev
-//   - Documentation:
-//     https://developer.mozilla.org/en-US/docs/Web/API/Storage/key
-func (ls *LocalStorage) Key(n int) (string, error) {
-	keyName := ls.key(n)
-	if keyName.IsNull() {
-		return "", os.ErrNotExist
-	}
-
-	return strings.TrimPrefix(keyName.String(), ls.prefix), nil
-}
-
-// Keys returns a list of all key names in local storage.
-func (ls *LocalStorage) Keys() []string {
-	keyNamesJson := utils.JSON.Call("stringify", ls.keys())
-
-	var keyNames []string
-	err := json.Unmarshal([]byte(keyNamesJson.String()), &keyNames)
-	if err != nil {
-		jww.FATAL.Panicf(
-			"Failed to JSON unmarshal localStorage key name list: %+v", err)
-	}
-
-	return keyNames
-}
-
-// Length returns the number of keys in localStorage. Underneath, it accesses
-// the property localStorage.length.
-//
-//   - Specification:
-//     https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-key-dev
-//   - Documentation:
-//     https://developer.mozilla.org/en-US/docs/Web/API/Storage/length
-func (ls *LocalStorage) Length() int {
-	return ls.length().Int()
-}
-
-// Wrappers for Javascript Storage methods and properties.
-func (ls *LocalStorage) getItem(keyName string) js.Value  { return ls.v.Call("getItem", keyName) }
-func (ls *LocalStorage) setItem(keyName, keyValue string) { ls.v.Call("setItem", keyName, keyValue) }
-func (ls *LocalStorage) removeItem(keyName string)        { ls.v.Call("removeItem", keyName) }
-func (ls *LocalStorage) clear()                           { ls.v.Call("clear") }
-func (ls *LocalStorage) key(n int) js.Value               { return ls.v.Call("key", n) }
-func (ls *LocalStorage) length() js.Value                 { return ls.v.Get("length") }
-func (ls *LocalStorage) keys() js.Value                   { return utils.Object.Call("keys", ls.v) }
diff --git a/storage/localStorage_test.go b/storage/localStorage_test.go
deleted file mode 100644
index 20e424108af9b7ed64c9c4ba00e348b121beefc4..0000000000000000000000000000000000000000
--- a/storage/localStorage_test.go
+++ /dev/null
@@ -1,271 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package storage
-
-import (
-	"bytes"
-	"github.com/pkg/errors"
-	"math/rand"
-	"os"
-	"strconv"
-	"testing"
-)
-
-// Tests that a value set with LocalStorage.SetItem and retrieved with
-// LocalStorage.GetItem matches the original.
-func TestLocalStorage_GetItem_SetItem(t *testing.T) {
-	values := map[string][]byte{
-		"key1": []byte("key value"),
-		"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
-		"key3": {0, 49, 0, 0, 0, 38, 249, 93, 242, 189, 222, 32, 138, 248, 121,
-			151, 42, 108, 82, 199, 163, 61, 4, 200, 140, 231, 225, 20, 35, 243,
-			253, 161, 61, 2, 227, 208, 173, 183, 33, 66, 236, 107, 105, 119, 26,
-			42, 44, 60, 109, 172, 38, 47, 220, 17, 129, 4, 234, 241, 141, 81,
-			84, 185, 32, 120, 115, 151, 128, 196, 143, 117, 222, 78, 44, 115,
-			109, 20, 249, 46, 158, 139, 231, 157, 54, 219, 141, 252},
-	}
-
-	for keyName, keyValue := range values {
-		jsStorage.SetItem(keyName, keyValue)
-
-		loadedValue, err := jsStorage.GetItem(keyName)
-		if err != nil {
-			t.Errorf("Failed to load %q: %+v", keyName, err)
-		}
-
-		if !bytes.Equal(keyValue, loadedValue) {
-			t.Errorf("Loaded value does not match original for %q"+
-				"\nexpected: %q\nreceived: %q", keyName, keyValue, loadedValue)
-		}
-	}
-}
-
-// Tests that LocalStorage.GetItem returns the error os.ErrNotExist when the key
-// does not exist in storage.
-func TestLocalStorage_GetItem_NotExistError(t *testing.T) {
-	_, err := jsStorage.GetItem("someKey")
-	if err == nil || !errors.Is(err, os.ErrNotExist) {
-		t.Errorf("Incorrect error for non existant key."+
-			"\nexpected: %v\nreceived: %v", os.ErrNotExist, err)
-	}
-}
-
-// Tests that LocalStorage.RemoveItem deletes a key from store and that it
-// cannot be retrieved.
-func TestLocalStorage_RemoveItem(t *testing.T) {
-	keyName := "key"
-	jsStorage.SetItem(keyName, []byte("value"))
-	jsStorage.RemoveItem(keyName)
-
-	_, err := jsStorage.GetItem(keyName)
-	if err == nil || !errors.Is(err, os.ErrNotExist) {
-		t.Errorf("Failed to remove %q: %+v", keyName, err)
-	}
-}
-
-// Tests that LocalStorage.Clear deletes all keys from storage.
-func TestLocalStorage_Clear(t *testing.T) {
-	for i := 0; i < 10; i++ {
-		jsStorage.SetItem(strconv.Itoa(i), []byte(strconv.Itoa(i)))
-	}
-
-	jsStorage.Clear()
-
-	l := jsStorage.Length()
-
-	if l > 0 {
-		t.Errorf("Clear did not delete all keys. Found %d keys.", l)
-	}
-}
-
-// Tests that LocalStorage.ClearPrefix deletes only the keys with the given
-// prefix.
-func TestLocalStorage_ClearPrefix(t *testing.T) {
-	s := newLocalStorage("")
-	s.clear()
-	prng := rand.New(rand.NewSource(11))
-	const numKeys = 10
-	var yesPrefix, noPrefix []string
-	prefix := "keyNamePrefix/"
-
-	for i := 0; i < numKeys; i++ {
-		keyName := "keyNum" + strconv.Itoa(i)
-		if prng.Intn(2) == 0 {
-			keyName = prefix + keyName
-			yesPrefix = append(yesPrefix, keyName)
-		} else {
-			noPrefix = append(noPrefix, keyName)
-		}
-
-		s.SetItem(keyName, []byte(strconv.Itoa(i)))
-	}
-
-	n := s.ClearPrefix(prefix)
-	if n != numKeys/2 {
-		t.Errorf("Incorrect number of keys.\nexpected: %d\nreceived: %d",
-			numKeys/2, n)
-	}
-
-	for _, keyName := range noPrefix {
-		if _, err := s.GetItem(keyName); err != nil {
-			t.Errorf("Could not get keyName %q: %+v", keyName, err)
-		}
-	}
-	for _, keyName := range yesPrefix {
-		keyValue, err := s.GetItem(keyName)
-		if err == nil || !errors.Is(err, os.ErrNotExist) {
-			t.Errorf("Found keyName %q: %q", keyName, keyValue)
-		}
-	}
-}
-
-// Tests that LocalStorage.ClearWASM deletes all the WASM keys from storage and
-// does not remove any others
-func TestLocalStorage_ClearWASM(t *testing.T) {
-	jsStorage.clear()
-	prng := rand.New(rand.NewSource(11))
-	const numKeys = 10
-	var yesPrefix, noPrefix []string
-
-	for i := 0; i < numKeys; i++ {
-		keyName := "keyNum" + strconv.Itoa(i)
-		if prng.Intn(2) == 0 {
-			yesPrefix = append(yesPrefix, keyName)
-			jsStorage.SetItem(keyName, []byte(strconv.Itoa(i)))
-		} else {
-			noPrefix = append(noPrefix, keyName)
-			jsStorage.setItem(keyName, strconv.Itoa(i))
-		}
-	}
-
-	n := jsStorage.ClearWASM()
-	if n != numKeys/2 {
-		t.Errorf("Incorrect number of keys.\nexpected: %d\nreceived: %d",
-			numKeys/2, n)
-	}
-
-	for _, keyName := range noPrefix {
-		if v := jsStorage.getItem(keyName); v.IsNull() {
-			t.Errorf("Could not get keyName %q.", keyName)
-		}
-	}
-	for _, keyName := range yesPrefix {
-		keyValue, err := jsStorage.GetItem(keyName)
-		if err == nil || !errors.Is(err, os.ErrNotExist) {
-			t.Errorf("Found keyName %q: %q", keyName, keyValue)
-		}
-	}
-}
-
-// Tests that LocalStorage.Key return all added keys when looping through all
-// indexes.
-func TestLocalStorage_Key(t *testing.T) {
-	jsStorage.clear()
-	values := map[string][]byte{
-		"key1": []byte("key value"),
-		"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
-		"key3": {0, 49, 0, 0, 0, 38, 249, 93},
-	}
-
-	for keyName, keyValue := range values {
-		jsStorage.SetItem(keyName, keyValue)
-	}
-
-	numKeys := len(values)
-	for i := 0; i < numKeys; i++ {
-		keyName, err := jsStorage.Key(i)
-		if err != nil {
-			t.Errorf("No key found for index %d: %+v", i, err)
-		}
-
-		if _, exists := values[keyName]; !exists {
-			t.Errorf("No key with name %q added to storage.", keyName)
-		}
-		delete(values, keyName)
-	}
-
-	if len(values) != 0 {
-		t.Errorf("%d keys not read from storage: %q", len(values), values)
-	}
-}
-
-// Tests that LocalStorage.Key returns the error os.ErrNotExist when the index
-// is greater than or equal to the number of keys.
-func TestLocalStorage_Key_NotExistError(t *testing.T) {
-	jsStorage.clear()
-	jsStorage.SetItem("key", []byte("value"))
-
-	_, err := jsStorage.Key(1)
-	if err == nil || !errors.Is(err, os.ErrNotExist) {
-		t.Errorf("Incorrect error for non existant key index."+
-			"\nexpected: %v\nreceived: %v", os.ErrNotExist, err)
-	}
-
-	_, err = jsStorage.Key(2)
-	if err == nil || !errors.Is(err, os.ErrNotExist) {
-		t.Errorf("Incorrect error for non existant key index."+
-			"\nexpected: %v\nreceived: %v", os.ErrNotExist, err)
-	}
-}
-
-// Tests that LocalStorage.Length returns the correct Length when adding and
-// removing various keys.
-func TestLocalStorage_Length(t *testing.T) {
-	jsStorage.clear()
-	values := map[string][]byte{
-		"key1": []byte("key value"),
-		"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
-		"key3": {0, 49, 0, 0, 0, 38, 249, 93},
-	}
-
-	i := 0
-	for keyName, keyValue := range values {
-		jsStorage.SetItem(keyName, keyValue)
-		i++
-
-		if jsStorage.Length() != i {
-			t.Errorf("Incorrect length.\nexpected: %d\nreceived: %d",
-				i, jsStorage.Length())
-		}
-	}
-
-	i = len(values)
-	for keyName := range values {
-		jsStorage.RemoveItem(keyName)
-		i--
-
-		if jsStorage.Length() != i {
-			t.Errorf("Incorrect length.\nexpected: %d\nreceived: %d",
-				i, jsStorage.Length())
-		}
-	}
-}
-
-// Tests that LocalStorage.Keys return a list that contains all the added keys.
-func TestLocalStorage_Keys(t *testing.T) {
-	s := newLocalStorage("")
-	s.clear()
-	values := map[string][]byte{
-		"key1": []byte("key value"),
-		"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
-		"key3": {0, 49, 0, 0, 0, 38, 249, 93},
-	}
-
-	for keyName, keyValue := range values {
-		s.SetItem(keyName, keyValue)
-	}
-
-	keys := s.Keys()
-	for i, keyName := range keys {
-		if _, exists := values[keyName]; !exists {
-			t.Errorf("Key %q does not exist (%d).", keyName, i)
-		}
-	}
-}
diff --git a/storage/password.go b/storage/password.go
index 36175e1002dbe3343a32fa41a9af239a9e13a7aa..7be49b310b54b7aa2764678f35d0b91550d2c491 100644
--- a/storage/password.go
+++ b/storage/password.go
@@ -12,16 +12,21 @@ package storage
 import (
 	"crypto/cipher"
 	"encoding/json"
-	"github.com/pkg/errors"
-	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
-	"gitlab.com/xx_network/crypto/csprng"
-	"golang.org/x/crypto/argon2"
-	"golang.org/x/crypto/blake2b"
-	"golang.org/x/crypto/chacha20poly1305"
 	"io"
 	"os"
 	"syscall/js"
+
+	"golang.org/x/crypto/argon2"
+	"golang.org/x/crypto/blake2b"
+	"golang.org/x/crypto/chacha20poly1305"
+
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/storage"
+	"gitlab.com/elixxir/wasm-utils/utils"
+	"gitlab.com/xx_network/crypto/csprng"
 )
 
 // Data lengths.
@@ -91,7 +96,7 @@ const (
 func GetOrInitPassword(_ js.Value, args []js.Value) any {
 	internalPassword, err := getOrInit(args[0].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -109,7 +114,7 @@ func GetOrInitPassword(_ js.Value, args []js.Value) any {
 func ChangeExternalPassword(_ js.Value, args []js.Value) any {
 	err := changeExternalPassword(args[0].String(), args[1].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -130,7 +135,7 @@ func VerifyPassword(_ js.Value, args []js.Value) any {
 // getOrInit is the private function for GetOrInitPassword that is used for
 // testing.
 func getOrInit(externalPassword string) ([]byte, error) {
-	localStorage := GetLocalStorage()
+	localStorage := storage.GetLocalStorage()
 	internalPassword, err := getInternalPassword(externalPassword, localStorage)
 	if err != nil {
 		if errors.Is(err, os.ErrNotExist) {
@@ -148,7 +153,7 @@ func getOrInit(externalPassword string) ([]byte, error) {
 // changeExternalPassword is the private function for ChangeExternalPassword
 // that is used for testing.
 func changeExternalPassword(oldExternalPassword, newExternalPassword string) error {
-	localStorage := GetLocalStorage()
+	localStorage := storage.GetLocalStorage()
 	internalPassword, err := getInternalPassword(
 		oldExternalPassword, localStorage)
 	if err != nil {
@@ -159,13 +164,17 @@ func changeExternalPassword(oldExternalPassword, newExternalPassword string) err
 	if err != nil {
 		return err
 	}
-	localStorage.SetItem(saltKey, salt)
+	if err = localStorage.Set(saltKey, salt); err != nil {
+		return errors.Wrapf(err, "localStorage: failed to set %q", saltKey)
+	}
 
 	key := deriveKey(newExternalPassword, salt, defaultParams())
 
 	encryptedInternalPassword := encryptPassword(
 		internalPassword, key, csprng.NewSystemRNG())
-	localStorage.SetItem(passwordKey, encryptedInternalPassword)
+	if err = localStorage.Set(passwordKey, encryptedInternalPassword); err != nil {
+		return errors.Wrapf(err, "localStorage: failed to set %q", passwordKey)
+	}
 
 	return nil
 }
@@ -173,14 +182,14 @@ func changeExternalPassword(oldExternalPassword, newExternalPassword string) err
 // verifyPassword is the private function for VerifyPassword that is used for
 // testing.
 func verifyPassword(externalPassword string) bool {
-	_, err := getInternalPassword(externalPassword, GetLocalStorage())
+	_, err := getInternalPassword(externalPassword, storage.GetLocalStorage())
 	return err == nil
 }
 
 // initInternalPassword generates a new internal password, stores an encrypted
 // version in local storage, and returns it.
 func initInternalPassword(externalPassword string,
-	localStorage *LocalStorage, csprng io.Reader,
+	localStorage *storage.LocalStorage, csprng io.Reader,
 	params argonParams) ([]byte, error) {
 	internalPassword := make([]byte, internalPasswordLen)
 
@@ -198,19 +207,28 @@ func initInternalPassword(externalPassword string,
 	if err != nil {
 		return nil, err
 	}
-	localStorage.SetItem(saltKey, salt)
+	if err = localStorage.Set(saltKey, salt); err != nil {
+		return nil,
+			errors.Wrapf(err, "localStorage: failed to set %q", saltKey)
+	}
 
 	// Store argon2 parameters
 	paramsData, err := json.Marshal(params)
 	if err != nil {
 		return nil, err
 	}
-	localStorage.SetItem(argonParamsKey, paramsData)
+	if err = localStorage.Set(argonParamsKey, paramsData); err != nil {
+		return nil,
+			errors.Wrapf(err, "localStorage: failed to set %q", argonParamsKey)
+	}
 
 	key := deriveKey(externalPassword, salt, params)
 
 	encryptedInternalPassword := encryptPassword(internalPassword, key, csprng)
-	localStorage.SetItem(passwordKey, encryptedInternalPassword)
+	if err = localStorage.Set(passwordKey, encryptedInternalPassword); err != nil {
+		return nil,
+			errors.Wrapf(err, "localStorage: failed to set %q", passwordKey)
+	}
 
 	return internalPassword, nil
 }
@@ -218,18 +236,18 @@ func initInternalPassword(externalPassword string,
 // getInternalPassword retrieves the internal password from local storage,
 // decrypts it, and returns it.
 func getInternalPassword(
-	externalPassword string, localStorage *LocalStorage) ([]byte, error) {
-	encryptedInternalPassword, err := localStorage.GetItem(passwordKey)
+	externalPassword string, localStorage *storage.LocalStorage) ([]byte, error) {
+	encryptedInternalPassword, err := localStorage.Get(passwordKey)
 	if err != nil {
 		return nil, errors.WithMessage(err, getPasswordStorageErr)
 	}
 
-	salt, err := localStorage.GetItem(saltKey)
+	salt, err := localStorage.Get(saltKey)
 	if err != nil {
 		return nil, errors.WithMessage(err, getSaltStorageErr)
 	}
 
-	paramsData, err := localStorage.GetItem(argonParamsKey)
+	paramsData, err := localStorage.Get(argonParamsKey)
 	if err != nil {
 		return nil, errors.WithMessage(err, getParamsStorageErr)
 	}
diff --git a/storage/password_test.go b/storage/password_test.go
index 24f1ed035197a1856c9f1750d2072609d9feb9c1..0e4c4c64105e93247cf24d1665360fdbd834a687 100644
--- a/storage/password_test.go
+++ b/storage/password_test.go
@@ -14,9 +14,11 @@ import (
 	"crypto/rand"
 	"encoding/base64"
 	"fmt"
-	"gitlab.com/xx_network/crypto/csprng"
 	"strings"
 	"testing"
+
+	"gitlab.com/elixxir/wasm-utils/storage"
+	"gitlab.com/xx_network/crypto/csprng"
 )
 
 // Tests that running getOrInit twice returns the same internal password both
@@ -77,7 +79,7 @@ func Test_changeExternalPassword(t *testing.T) {
 // Tests that verifyPassword returns true for a valid password and false for an
 // invalid password
 func Test_verifyPassword(t *testing.T) {
-	GetLocalStorage().Clear()
+	storage.GetLocalStorage().Clear()
 	externalPassword := "myPassword"
 
 	if _, err := getOrInit(externalPassword); err != nil {
@@ -97,7 +99,7 @@ func Test_verifyPassword(t *testing.T) {
 // the encrypted one saved to local storage.
 func Test_initInternalPassword(t *testing.T) {
 	externalPassword := "myPassword"
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	rng := csprng.NewSystemRNG()
 
 	internalPassword, err := initInternalPassword(
@@ -107,14 +109,14 @@ func Test_initInternalPassword(t *testing.T) {
 	}
 
 	// Attempt to retrieve encrypted internal password from storage
-	encryptedInternalPassword, err := ls.GetItem(passwordKey)
+	encryptedInternalPassword, err := ls.Get(passwordKey)
 	if err != nil {
 		t.Errorf(
 			"Failed to load encrypted internal password from storage: %+v", err)
 	}
 
 	// Attempt to retrieve salt from storage
-	salt, err := ls.GetItem(saltKey)
+	salt, err := ls.Get(saltKey)
 	if err != nil {
 		t.Errorf("Failed to load salt from storage: %+v", err)
 	}
@@ -138,7 +140,7 @@ func Test_initInternalPassword(t *testing.T) {
 // error when read.
 func Test_initInternalPassword_CsprngReadError(t *testing.T) {
 	externalPassword := "myPassword"
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	b := bytes.NewBuffer([]byte{})
 
 	expectedErr := strings.Split(readInternalPasswordErr, "%")[0]
@@ -154,7 +156,7 @@ func Test_initInternalPassword_CsprngReadError(t *testing.T) {
 // return enough bytes.
 func Test_initInternalPassword_CsprngReadNumBytesError(t *testing.T) {
 	externalPassword := "myPassword"
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	b := bytes.NewBuffer(make([]byte, internalPasswordLen/2))
 
 	expectedErr := fmt.Sprintf(
@@ -171,7 +173,7 @@ func Test_initInternalPassword_CsprngReadNumBytesError(t *testing.T) {
 // to local storage by initInternalPassword.
 func Test_getInternalPassword(t *testing.T) {
 	externalPassword := "myPassword"
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	rng := csprng.NewSystemRNG()
 
 	internalPassword, err := initInternalPassword(
@@ -196,7 +198,7 @@ func Test_getInternalPassword(t *testing.T) {
 // loaded from local storage.
 func Test_getInternalPassword_LocalStorageGetPasswordError(t *testing.T) {
 	externalPassword := "myPassword"
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	ls.Clear()
 
 	expectedErr := strings.Split(getPasswordStorageErr, "%")[0]
@@ -212,9 +214,11 @@ func Test_getInternalPassword_LocalStorageGetPasswordError(t *testing.T) {
 // loaded from local storage.
 func Test_getInternalPassword_LocalStorageGetError(t *testing.T) {
 	externalPassword := "myPassword"
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	ls.Clear()
-	ls.SetItem(passwordKey, []byte("password"))
+	if err := ls.Set(passwordKey, []byte("password")); err != nil {
+		t.Fatalf("Failed to set %q: %+v", passwordKey, err)
+	}
 
 	expectedErr := strings.Split(getSaltStorageErr, "%")[0]
 
@@ -229,11 +233,17 @@ func Test_getInternalPassword_LocalStorageGetError(t *testing.T) {
 // decrypted.
 func Test_getInternalPassword_DecryptPasswordError(t *testing.T) {
 	externalPassword := "myPassword"
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	ls.Clear()
-	ls.SetItem(saltKey, []byte("salt"))
-	ls.SetItem(passwordKey, []byte("password"))
-	ls.SetItem(argonParamsKey, []byte(`{"Time": 1, "Memory": 65536, "Threads": 4}`))
+	if err := ls.Set(saltKey, []byte("salt")); err != nil {
+		t.Errorf("failed to set %q: %+v", saltKey, err)
+	}
+	if err := ls.Set(passwordKey, []byte("password")); err != nil {
+		t.Errorf("failed to set %q: %+v", passwordKey, err)
+	}
+	if err := ls.Set(argonParamsKey, []byte(`{"Time": 1, "Memory": 65536, "Threads": 4}`)); err != nil {
+		t.Errorf("failed to set %q: %+v", argonParamsKey, err)
+	}
 
 	expectedErr := strings.Split(decryptPasswordErr, "%")[0]
 
diff --git a/storage/purge.go b/storage/purge.go
index b80481b470863c32dee6cad894858cb081a08abe..9cd7dd4bf69f2ce7cbb131c88b757058db758356 100644
--- a/storage/purge.go
+++ b/storage/purge.go
@@ -10,13 +10,15 @@
 package storage
 
 import (
+	"sync/atomic"
+	"syscall/js"
+
 	"github.com/hack-pad/go-indexeddb/idb"
-	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
+
 	"gitlab.com/elixxir/client/v4/storage/utility"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
-	"sync/atomic"
-	"syscall/js"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/storage"
 )
 
 // numClientsRunning is an atomic that tracks the current number of Cmix
@@ -57,22 +59,21 @@ func Purge(_ js.Value, args []js.Value) any {
 
 	// Check the password
 	if !verifyPassword(userPassword) {
-		utils.Throw(utils.TypeError, errors.New("invalid password"))
+		exception.Throwf("invalid password")
 		return nil
 	}
 
 	// Verify all Cmix followers are stopped
 	if n := atomic.LoadUint64(&numClientsRunning); n != 0 {
-		utils.Throw(utils.TypeError, errors.Errorf(
-			"%d cMix followers running; all need to be stopped", n))
+		exception.Throwf("%d cMix followers running; all need to be stopped", n)
 		return nil
 	}
 
 	// Get all indexedDb database names
 	databaseList, err := GetIndexedDbList()
 	if err != nil {
-		utils.Throw(utils.TypeError, errors.Errorf(
-			"failed to get list of indexedDb database names: %+v", err))
+		exception.Throwf(
+			"failed to get list of indexedDb database names: %+v", err)
 		return nil
 	}
 	jww.DEBUG.Printf("[PURGE] Found %d databases to delete: %s",
@@ -82,26 +83,34 @@ func Purge(_ js.Value, args []js.Value) any {
 	for dbName := range databaseList {
 		_, err = idb.Global().DeleteDatabase(dbName)
 		if err != nil {
-			utils.Throw(utils.TypeError, errors.Errorf(
-				"failed to delete indexedDb database %q: %+v", dbName, err))
+			exception.Throwf(
+				"failed to delete indexedDb database %q: %+v", dbName, err)
 			return nil
 		}
 	}
 
 	// Get local storage
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 
 	// Clear all local storage saved by this WASM project
-	n := ls.ClearWASM()
+	n := ls.Clear()
 	jww.DEBUG.Printf("[PURGE] Cleared %d WASM keys in local storage", n)
 
 	// Clear all EKV from local storage
-	n = ls.ClearPrefix(storageDirectory)
+	keys := ls.LocalStorageUNSAFE().KeysPrefix(storageDirectory)
+	n = len(keys)
+	for _, keyName := range keys {
+		ls.LocalStorageUNSAFE().RemoveItem(keyName)
+	}
 	jww.DEBUG.Printf("[PURGE] Cleared %d keys with the prefix %q (for EKV)",
 		n, storageDirectory)
 
 	// Clear all NDFs saved to local storage
-	n = ls.ClearPrefix(utility.NdfStorageKeyNamePrefix)
+	keys = ls.LocalStorageUNSAFE().KeysPrefix(utility.NdfStorageKeyNamePrefix)
+	n = len(keys)
+	for _, keyName := range keys {
+		ls.LocalStorageUNSAFE().RemoveItem(keyName)
+	}
 	jww.DEBUG.Printf("[PURGE] Cleared %d keys with the prefix %q (for NDF)",
 		n, utility.NdfStorageKeyNamePrefix)
 
diff --git a/storage/version.go b/storage/version.go
index b0f192ab24f8ad80d1fb9a9a5c96177f67545440..5fa7e439af29a96c66b22c92b86db42c384c121f 100644
--- a/storage/version.go
+++ b/storage/version.go
@@ -17,6 +17,7 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 
 	"gitlab.com/elixxir/client/v4/bindings"
+	"gitlab.com/elixxir/wasm-utils/storage"
 )
 
 // SEMVER is the current semantic version of xxDK WASM.
@@ -35,11 +36,11 @@ const (
 // On first load, only the xxDK WASM and xxDK client versions are stored.
 func CheckAndStoreVersions() error {
 	return checkAndStoreVersions(
-		SEMVER, bindings.GetVersion(), GetLocalStorage())
+		SEMVER, bindings.GetVersion(), storage.GetLocalStorage())
 }
 
 func checkAndStoreVersions(
-	currentWasmVer, currentClientVer string, ls *LocalStorage) error {
+	currentWasmVer, currentClientVer string, ls *storage.LocalStorage) error {
 	// Get the stored client version, if it exists
 	storedClientVer, err :=
 		initOrLoadStoredSemver(clientVerKey, currentClientVer, ls)
@@ -76,8 +77,12 @@ func checkAndStoreVersions(
 	// Upgrade path code goes here
 
 	// Save current versions
-	ls.SetItem(clientVerKey, []byte(currentClientVer))
-	ls.SetItem(semverKey, []byte(currentWasmVer))
+	if err = ls.Set(clientVerKey, []byte(currentClientVer)); err != nil {
+		return errors.Wrapf(err, "localStorage: failed to set %q", clientVerKey)
+	}
+	if err = ls.Set(semverKey, []byte(currentWasmVer)); err != nil {
+		return errors.Wrapf(err, "localStorage: failed to set %q", semverKey)
+	}
 
 	return nil
 }
@@ -86,13 +91,16 @@ func checkAndStoreVersions(
 // local storage. If no version is stored, then the current version is stored
 // and returned.
 func initOrLoadStoredSemver(
-	key, currentVersion string, ls *LocalStorage) (string, error) {
-	storedVersion, err := ls.GetItem(key)
+	key, currentVersion string, ls *storage.LocalStorage) (string, error) {
+	storedVersion, err := ls.Get(key)
 	if err != nil {
 		if errors.Is(err, os.ErrNotExist) {
 			// Save the current version if this is the first run
 			jww.INFO.Printf("Initialising %s to v%s", key, currentVersion)
-			ls.SetItem(key, []byte(currentVersion))
+			if err = ls.Set(key, []byte(currentVersion)); err != nil {
+				return "",
+					errors.Wrapf(err, "localStorage: failed to set %q", key)
+			}
 			return currentVersion, nil
 		} else {
 			// If the item exists, but cannot be loaded, return an error
diff --git a/storage/version_test.go b/storage/version_test.go
index a8ead72e52a53d9840936a7deb6865d9aa30f201..27043680fea08beb01c6584557335a308d4c457a 100644
--- a/storage/version_test.go
+++ b/storage/version_test.go
@@ -11,12 +11,14 @@ package storage
 
 import (
 	"testing"
+
+	"gitlab.com/elixxir/wasm-utils/storage"
 )
 
 // Tests that checkAndStoreVersions correct initialises the client and WASM
 // versions on first run and upgrades them correctly on subsequent runs.
 func Test_checkAndStoreVersions(t *testing.T) {
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	ls.Clear()
 	oldWasmVer := "0.1"
 	newWasmVer := "1.0"
@@ -28,7 +30,7 @@ func Test_checkAndStoreVersions(t *testing.T) {
 	}
 
 	// Check client version
-	storedClientVer, err := ls.GetItem(clientVerKey)
+	storedClientVer, err := ls.Get(clientVerKey)
 	if err != nil {
 		t.Errorf("Failed to get client version from storage: %+v", err)
 	}
@@ -38,7 +40,7 @@ func Test_checkAndStoreVersions(t *testing.T) {
 	}
 
 	// Check WASM version
-	storedWasmVer, err := ls.GetItem(semverKey)
+	storedWasmVer, err := ls.Get(semverKey)
 	if err != nil {
 		t.Errorf("Failed to get WASM version from storage: %+v", err)
 	}
@@ -53,7 +55,7 @@ func Test_checkAndStoreVersions(t *testing.T) {
 	}
 
 	// Check client version
-	storedClientVer, err = ls.GetItem(clientVerKey)
+	storedClientVer, err = ls.Get(clientVerKey)
 	if err != nil {
 		t.Errorf("Failed to get client version from storage: %+v", err)
 	}
@@ -63,7 +65,7 @@ func Test_checkAndStoreVersions(t *testing.T) {
 	}
 
 	// Check WASM version
-	storedWasmVer, err = ls.GetItem(semverKey)
+	storedWasmVer, err = ls.Get(semverKey)
 	if err != nil {
 		t.Errorf("Failed to get WASM version from storage: %+v", err)
 	}
@@ -76,7 +78,7 @@ func Test_checkAndStoreVersions(t *testing.T) {
 // Tests that initOrLoadStoredSemver initialises the correct version on first
 // run and returns the same version on subsequent runs.
 func Test_initOrLoadStoredSemver(t *testing.T) {
-	ls := GetLocalStorage()
+	ls := storage.GetLocalStorage()
 	key := "testKey"
 	oldVersion := "0.1"
 
diff --git a/utils/array.go b/utils/array.go
deleted file mode 100644
index 3597d0ba9cca229e1141c164d9e1204cf56c117a..0000000000000000000000000000000000000000
--- a/utils/array.go
+++ /dev/null
@@ -1,71 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package utils
-
-import (
-	"bytes"
-	"encoding/base64"
-	"syscall/js"
-)
-
-// Uint8ArrayToBase64 encodes an uint8 array to a base 64 string.
-//
-// Parameters:
-//   - args[0] - Javascript 8-bit unsigned integer array (Uint8Array).
-//
-// Returns:
-//   - Base 64 encoded string (string).
-func Uint8ArrayToBase64(_ js.Value, args []js.Value) any {
-	return base64.StdEncoding.EncodeToString(CopyBytesToGo(args[0]))
-}
-
-// Base64ToUint8Array decodes a base 64 encoded string to a Uint8Array.
-//
-// Parameters:
-//   - args[0] - Base 64 encoded string (string).
-//
-// Returns:
-//   - Javascript 8-bit unsigned integer array (Uint8Array).
-//   - Throws TypeError if decoding the string fails.
-func Base64ToUint8Array(_ js.Value, args []js.Value) any {
-	b, err := base64ToUint8Array(args[0])
-	if err != nil {
-		Throw(TypeError, err)
-	}
-
-	return b
-}
-
-// base64ToUint8Array is a helper function that returns an error instead of
-// throwing it.
-func base64ToUint8Array(base64String js.Value) (js.Value, error) {
-	b, err := base64.StdEncoding.DecodeString(base64String.String())
-	if err != nil {
-		return js.Value{}, err
-	}
-
-	return CopyBytesToJS(b), nil
-}
-
-// Uint8ArrayEquals returns true if the two Uint8Array are equal and false
-// otherwise.
-//
-// Parameters:
-//   - args[0] - Array A (Uint8Array).
-//   - args[1] - Array B (Uint8Array).
-//
-// Returns:
-//   - If the two arrays are equal (boolean).
-func Uint8ArrayEquals(_ js.Value, args []js.Value) any {
-	a := CopyBytesToGo(args[0])
-	b := CopyBytesToGo(args[1])
-
-	return bytes.Equal(a, b)
-}
diff --git a/utils/array_test.go b/utils/array_test.go
deleted file mode 100644
index 0353d1cce9155cf47e4c8e21132809b6d7d1915c..0000000000000000000000000000000000000000
--- a/utils/array_test.go
+++ /dev/null
@@ -1,114 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package utils
-
-import (
-	"encoding/base64"
-	"fmt"
-	"strings"
-	"syscall/js"
-	"testing"
-)
-
-var testBytes = [][]byte{
-	nil,
-	{},
-	{0},
-	{0, 1, 2, 3},
-	{214, 108, 207, 78, 229, 11, 42, 219, 42, 87, 205, 104, 252, 73, 223,
-		229, 145, 209, 79, 111, 34, 96, 238, 127, 11, 105, 114, 62, 239,
-		130, 145, 82, 3},
-}
-
-// Tests that a series of Uint8Array Javascript objects are correctly converted
-// to base 64 strings with Uint8ArrayToBase64.
-func TestUint8ArrayToBase64(t *testing.T) {
-	for i, val := range testBytes {
-		// Create Uint8Array and set each element individually
-		jsBytes := Uint8Array.New(len(val))
-		for j, v := range val {
-			jsBytes.SetIndex(j, v)
-		}
-
-		jsB64 := Uint8ArrayToBase64(js.Value{}, []js.Value{jsBytes})
-
-		expected := base64.StdEncoding.EncodeToString(val)
-
-		if expected != jsB64 {
-			t.Errorf("Did not receive expected base64 encoded string (%d)."+
-				"\nexpected: %s\nreceived: %s", i, expected, jsB64)
-		}
-	}
-}
-
-// Tests that Base64ToUint8Array correctly decodes a series of base 64 encoded
-// strings into Uint8Array.
-func TestBase64ToUint8Array(t *testing.T) {
-	for i, val := range testBytes {
-		b64 := base64.StdEncoding.EncodeToString(val)
-		jsArr, err := base64ToUint8Array(js.ValueOf(b64))
-		if err != nil {
-			t.Errorf("Failed to convert js.Value to base 64: %+v", err)
-		}
-
-		// Generate the expected string to match the output of toString() on a
-		// Uint8Array
-		expected := strings.ReplaceAll(fmt.Sprintf("%d", val), " ", ",")[1:]
-		expected = expected[:len(expected)-1]
-
-		// Get the string value of the Uint8Array
-		jsString := jsArr.Call("toString").String()
-
-		if expected != jsString {
-			t.Errorf("Failed to recevie expected string representation of "+
-				"the Uint8Array (%d).\nexpected: %s\nreceived: %s",
-				i, expected, jsString)
-		}
-	}
-}
-
-// Tests that a base 64 encoded string decoded to Uint8Array via
-// Base64ToUint8Array and back to a base 64 encoded string via
-// Uint8ArrayToBase64 matches the original.
-func TestBase64ToUint8ArrayUint8ArrayToBase64(t *testing.T) {
-	for i, val := range testBytes {
-		b64 := base64.StdEncoding.EncodeToString(val)
-		jsArr, err := base64ToUint8Array(js.ValueOf(b64))
-		if err != nil {
-			t.Errorf("Failed to convert js.Value to base 64: %+v", err)
-		}
-
-		jsB64 := Uint8ArrayToBase64(js.Value{}, []js.Value{jsArr})
-
-		if b64 != jsB64 {
-			t.Errorf("JSON from Uint8Array does not match original (%d)."+
-				"\nexpected: %s\nreceived: %s", i, b64, jsB64)
-		}
-	}
-}
-
-func TestUint8ArrayEquals(t *testing.T) {
-	for i, val := range testBytes {
-		// Create Uint8Array and set each element individually
-		jsBytesA := Uint8Array.New(len(val))
-		for j, v := range val {
-			jsBytesA.SetIndex(j, v)
-		}
-
-		jsBytesB := CopyBytesToJS(val)
-
-		if !Uint8ArrayEquals(js.Value{}, []js.Value{jsBytesA, jsBytesB}).(bool) {
-			t.Errorf("Two equal byte slices were found to be different (%d)."+
-				"\nexpected: %s\nreceived: %s", i,
-				jsBytesA.Call("toString").String(),
-				jsBytesB.Call("toString").String())
-		}
-	}
-}
diff --git a/utils/convert.go b/utils/convert.go
deleted file mode 100644
index b1f2cd10172bca7e88ff6c77931c754ab1b7f1d8..0000000000000000000000000000000000000000
--- a/utils/convert.go
+++ /dev/null
@@ -1,62 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package utils
-
-import (
-	"encoding/json"
-	"syscall/js"
-)
-
-// CopyBytesToGo copies the [Uint8Array] stored in the [js.Value] to []byte.
-// This is a wrapper for [js.CopyBytesToGo] to make it more convenient.
-func CopyBytesToGo(src js.Value) []byte {
-	b := make([]byte, src.Length())
-	js.CopyBytesToGo(b, src)
-	return b
-}
-
-// CopyBytesToJS copies the []byte to a [Uint8Array] stored in a [js.Value].
-// This is a wrapper for [js.CopyBytesToJS] to make it more convenient.
-func CopyBytesToJS(src []byte) js.Value {
-	dst := Uint8Array.New(len(src))
-	js.CopyBytesToJS(dst, src)
-	return dst
-}
-
-// JsToJson converts the Javascript value to JSON.
-func JsToJson(value js.Value) string {
-	if value.IsUndefined() {
-		return "null"
-	}
-
-	return JSON.Call("stringify", value).String()
-}
-
-// JsonToJS converts a JSON bytes input to a [js.Value] of the object subtype.
-func JsonToJS(inputJson []byte) (js.Value, error) {
-	var jsObj map[string]any
-	err := json.Unmarshal(inputJson, &jsObj)
-	if err != nil {
-		return js.ValueOf(nil), err
-	}
-
-	return js.ValueOf(jsObj), nil
-}
-
-// JsErrorToJson converts the Javascript error to JSON. This should be used for
-// all Javascript error objects instead of JsonToJS.
-func JsErrorToJson(value js.Value) string {
-	if value.IsUndefined() {
-		return "null"
-	}
-
-	properties := Object.Call("getOwnPropertyNames", value)
-	return JSON.Call("stringify", value, properties).String()
-}
diff --git a/utils/convert_test.go b/utils/convert_test.go
deleted file mode 100644
index 508c27f783f1365f28b4b7b78b7389fc4d3ff1a6..0000000000000000000000000000000000000000
--- a/utils/convert_test.go
+++ /dev/null
@@ -1,305 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package utils
-
-import (
-	"encoding/base64"
-	"encoding/json"
-	"sort"
-	"syscall/js"
-	"testing"
-)
-
-import (
-	"bytes"
-	"fmt"
-	"strings"
-)
-
-// Tests that CopyBytesToGo returns a byte slice that matches the Uint8Array.
-func TestCopyBytesToGo(t *testing.T) {
-	for i, val := range testBytes {
-		// Create Uint8Array and set each element individually
-		jsBytes := Uint8Array.New(len(val))
-		for j, v := range val {
-			jsBytes.SetIndex(j, v)
-		}
-
-		goBytes := CopyBytesToGo(jsBytes)
-
-		if !bytes.Equal(val, goBytes) {
-			t.Errorf("Failed to recevie expected bytes from Uint8Array (%d)."+
-				"\nexpected: %d\nreceived: %d",
-				i, val, goBytes)
-		}
-	}
-}
-
-// Tests that CopyBytesToJS returns a Javascript Uint8Array with values matching
-// the original byte slice.
-func TestCopyBytesToJS(t *testing.T) {
-	for i, val := range testBytes {
-		jsBytes := CopyBytesToJS(val)
-
-		// Generate the expected string to match the output of toString() on a
-		// Uint8Array
-		expected := strings.ReplaceAll(fmt.Sprintf("%d", val), " ", ",")[1:]
-		expected = expected[:len(expected)-1]
-
-		// Get the string value of the Uint8Array
-		jsString := jsBytes.Call("toString").String()
-
-		if expected != jsString {
-			t.Errorf("Failed to recevie expected string representation of "+
-				"the Uint8Array (%d).\nexpected: %s\nreceived: %s",
-				i, expected, jsString)
-		}
-	}
-}
-
-// Tests that a byte slice converted to Javascript via CopyBytesToJS and
-// converted back to Go via CopyBytesToGo matches the original.
-func TestCopyBytesToJSCopyBytesToGo(t *testing.T) {
-	for i, val := range testBytes {
-		jsBytes := CopyBytesToJS(val)
-		goBytes := CopyBytesToGo(jsBytes)
-
-		if !bytes.Equal(val, goBytes) {
-			t.Errorf("Failed to recevie expected bytes from Uint8Array (%d)."+
-				"\nexpected: %d\nreceived: %d",
-				i, val, goBytes)
-		}
-	}
-
-}
-
-// Tests that JsToJson can convert a Javascript object to JSON that matches the
-// output of json.Marshal on the Go version of the same object.
-func TestJsToJson(t *testing.T) {
-	testObj := map[string]any{
-		"nil":    nil,
-		"bool":   true,
-		"int":    1,
-		"float":  1.5,
-		"string": "I am string",
-		"array":  []any{1, 2, 3},
-		"object": map[string]any{"int": 5},
-	}
-
-	expected, err := json.Marshal(testObj)
-	if err != nil {
-		t.Errorf("Failed to JSON marshal test object: %+v", err)
-	}
-
-	jsJson := JsToJson(js.ValueOf(testObj))
-
-	// Javascript does not return the JSON object fields sorted so the letters
-	// of each Javascript string are sorted and compared
-	er := []rune(string(expected))
-	sort.SliceStable(er, func(i, j int) bool { return er[i] < er[j] })
-	jj := []rune(jsJson)
-	sort.SliceStable(jj, func(i, j int) bool { return jj[i] < jj[j] })
-
-	if string(er) != string(jj) {
-		t.Errorf("Recieved incorrect JSON from Javascript object."+
-			"\nexpected: %s\nreceived: %s", expected, jsJson)
-	}
-}
-
-// Tests that JsToJson return a null object when the Javascript object is
-// undefined.
-func TestJsToJson_Undefined(t *testing.T) {
-	expected, err := json.Marshal(nil)
-	if err != nil {
-		t.Errorf("Failed to JSON marshal test object: %+v", err)
-	}
-
-	jsJson := JsToJson(js.Undefined())
-
-	if string(expected) != jsJson {
-		t.Errorf("Recieved incorrect JSON from Javascript object."+
-			"\nexpected: %s\nreceived: %s", expected, jsJson)
-	}
-}
-
-// Tests that JsonToJS can convert a JSON object with multiple types to a
-// Javascript object and that all values match.
-func TestJsonToJS(t *testing.T) {
-	testObj := map[string]any{
-		"nil":    nil,
-		"bool":   true,
-		"int":    1,
-		"float":  1.5,
-		"string": "I am string",
-		"bytes":  []byte{1, 2, 3},
-		"array":  []any{1, 2, 3},
-		"object": map[string]any{"int": 5},
-	}
-	jsonData, err := json.Marshal(testObj)
-	if err != nil {
-		t.Errorf("Failed to JSON marshal test object: %+v", err)
-	}
-
-	jsObj, err := JsonToJS(jsonData)
-	if err != nil {
-		t.Errorf("Failed to convert JSON to Javascript object: %+v", err)
-	}
-
-	for key, val := range testObj {
-		jsVal := jsObj.Get(key)
-		switch key {
-		case "nil":
-			if !jsVal.IsNull() {
-				t.Errorf("Key %s is not null.", key)
-			}
-		case "bool":
-			if jsVal.Bool() != val {
-				t.Errorf("Incorrect value for key %s."+
-					"\nexpected: %t\nreceived: %t", key, val, jsVal.Bool())
-			}
-		case "int":
-			if jsVal.Int() != val {
-				t.Errorf("Incorrect value for key %s."+
-					"\nexpected: %d\nreceived: %d", key, val, jsVal.Int())
-			}
-		case "float":
-			if jsVal.Float() != val {
-				t.Errorf("Incorrect value for key %s."+
-					"\nexpected: %f\nreceived: %f", key, val, jsVal.Float())
-			}
-		case "string":
-			if jsVal.String() != val {
-				t.Errorf("Incorrect value for key %s."+
-					"\nexpected: %s\nreceived: %s", key, val, jsVal.String())
-			}
-		case "bytes":
-			if jsVal.String() != base64.StdEncoding.EncodeToString(val.([]byte)) {
-				t.Errorf("Incorrect value for key %s."+
-					"\nexpected: %s\nreceived: %s", key,
-					base64.StdEncoding.EncodeToString(val.([]byte)),
-					jsVal.String())
-			}
-		case "array":
-			for i, v := range val.([]any) {
-				if jsVal.Index(i).Int() != v {
-					t.Errorf("Incorrect value for key %s index %d."+
-						"\nexpected: %d\nreceived: %d",
-						key, i, v, jsVal.Index(i).Int())
-				}
-			}
-		case "object":
-			if jsVal.Get("int").Int() != val.(map[string]any)["int"] {
-				t.Errorf("Incorrect value for key %s."+
-					"\nexpected: %d\nreceived: %d", key,
-					val.(map[string]any)["int"], jsVal.Get("int").Int())
-			}
-		}
-	}
-}
-
-// Tests that JSON can be converted to a Javascript object via JsonToJS and back
-// to JSON using JsToJson and matches the original.
-func TestJsonToJSJsToJson(t *testing.T) {
-	testObj := map[string]any{
-		"nil":    nil,
-		"bool":   true,
-		"int":    1,
-		"float":  1.5,
-		"string": "I am string",
-		"bytes":  []byte{1, 2, 3},
-		"array":  []any{1, 2, 3},
-		"object": map[string]any{"int": 5},
-	}
-	jsonData, err := json.Marshal(testObj)
-	if err != nil {
-		t.Errorf("Failed to JSON marshal test object: %+v", err)
-	}
-
-	jsObj, err := JsonToJS(jsonData)
-	if err != nil {
-		t.Errorf("Failed to convert the Javascript object to JSON: %+v", err)
-	}
-
-	jsJson := JsToJson(jsObj)
-
-	// Javascript does not return the JSON object fields sorted so the letters
-	// of each Javascript string are sorted and compared
-	er := []rune(string(jsonData))
-	sort.SliceStable(er, func(i, j int) bool { return er[i] < er[j] })
-	jj := []rune(jsJson)
-	sort.SliceStable(jj, func(i, j int) bool { return jj[i] < jj[j] })
-
-	if string(er) != string(jj) {
-		t.Errorf("JSON from Javascript does not match original."+
-			"\nexpected: %s\nreceived: %s", jsonData, jsJson)
-	}
-}
-
-// Tests that JsErrorToJson can convert a Javascript object to JSON that matches
-// the output of json.Marshal on the Go version of the same object.
-func TestJsErrorToJson(t *testing.T) {
-	testObj := map[string]any{
-		"nil":    nil,
-		"bool":   true,
-		"int":    1,
-		"float":  1.5,
-		"string": "I am string",
-		"array":  []any{1, 2, 3},
-		"object": map[string]any{"int": 5},
-	}
-
-	expected, err := json.Marshal(testObj)
-	if err != nil {
-		t.Errorf("Failed to JSON marshal test object: %+v", err)
-	}
-
-	jsJson := JsErrorToJson(js.ValueOf(testObj))
-
-	// Javascript does not return the JSON object fields sorted so the letters
-	// of each Javascript string are sorted and compared
-	er := []rune(string(expected))
-	sort.SliceStable(er, func(i, j int) bool { return er[i] < er[j] })
-	jj := []rune(jsJson)
-	sort.SliceStable(jj, func(i, j int) bool { return jj[i] < jj[j] })
-
-	if string(er) != string(jj) {
-		t.Errorf("Recieved incorrect JSON from Javascript object."+
-			"\nexpected: %s\nreceived: %s", expected, jsJson)
-	}
-}
-
-// Tests that JsErrorToJson return a null object when the Javascript object is
-// undefined.
-func TestJsErrorToJson_Undefined(t *testing.T) {
-	expected, err := json.Marshal(nil)
-	if err != nil {
-		t.Errorf("Failed to JSON marshal test object: %+v", err)
-	}
-
-	jsJson := JsErrorToJson(js.Undefined())
-
-	if string(expected) != jsJson {
-		t.Errorf("Recieved incorrect JSON from Javascript object."+
-			"\nexpected: %s\nreceived: %s", expected, jsJson)
-	}
-}
-
-// Tests that JsErrorToJson returns a JSON object containing the original error
-// string.
-func TestJsErrorToJson_ErrorObject(t *testing.T) {
-	expected := "An error"
-	jsErr := Error.New(expected)
-	jsJson := JsErrorToJson(jsErr)
-
-	if !strings.Contains(jsJson, expected) {
-		t.Errorf("Recieved incorrect JSON from Javascript error."+
-			"\nexpected: %s\nreceived: %s", expected, jsJson)
-	}
-}
diff --git a/utils/errors.go b/utils/errors.go
deleted file mode 100644
index 2e1cbacbce3b7c70a67f52e1217a76ef63f887b5..0000000000000000000000000000000000000000
--- a/utils/errors.go
+++ /dev/null
@@ -1,71 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package utils
-
-import (
-	"fmt"
-	"syscall/js"
-)
-
-// JsError converts the error to a Javascript Error.
-func JsError(err error) js.Value {
-	return Error.New(err.Error())
-}
-
-// JsTrace converts the error to a Javascript Error that includes the error's
-// stack trace.
-func JsTrace(err error) js.Value {
-	return Error.New(fmt.Sprintf("%+v", err))
-}
-
-// Throw function stub to throws Javascript exceptions. The exception must be
-// one of the defined Exception below. Any other error types will result in an
-// error.
-func Throw(exception Exception, err error) {
-	throw(exception, fmt.Sprintf("%+v", err))
-}
-
-func throw(exception Exception, message string)
-
-// Exception are the possible Javascript error types that can be thrown.
-type Exception string
-
-const (
-	// EvalError occurs when error has occurred in the eval() function.
-	//
-	// Deprecated: This exception is not thrown by JavaScript anymore, however
-	// the EvalError object remains for compatibility.
-	EvalError Exception = "EvalError"
-
-	// RangeError occurs when a numeric variable or parameter is outside its
-	// valid range.
-	RangeError Exception = "RangeError"
-
-	// ReferenceError occurs when a variable that does not exist (or hasn't yet
-	// been initialized) in the current scope is referenced.
-	ReferenceError Exception = "ReferenceError"
-
-	// SyntaxError occurs when trying to interpret syntactically invalid code.
-	SyntaxError Exception = "SyntaxError"
-
-	// TypeError occurs when an operation could not be performed, typically (but
-	// not exclusively) when a value is not of the expected type.
-	//
-	// A TypeError may be thrown when:
-	//  - an operand or argument passed to a function is incompatible with the
-	//    type expected by that operator or function; or
-	//  - when attempting to modify a value that cannot be changed; or
-	//  - when attempting to use a value in an inappropriate way.
-	TypeError Exception = "TypeError"
-
-	// URIError occurs when a global URI handling function was used in a wrong
-	// way.
-	URIError Exception = "URIError"
-)
diff --git a/utils/errors_test.go b/utils/errors_test.go
deleted file mode 100644
index f9965e34878f0cd507e2839482e1f38201a99055..0000000000000000000000000000000000000000
--- a/utils/errors_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package utils
-
-import (
-	"fmt"
-	"github.com/pkg/errors"
-	"testing"
-)
-
-// Tests that TestJsError returns a Javascript Error object with the expected
-// message.
-func TestJsError(t *testing.T) {
-	err := errors.New("test error")
-	expectedErr := err.Error()
-	jsError := JsError(err).Get("message").String()
-
-	if jsError != expectedErr {
-		t.Errorf("Failed to get expected error message."+
-			"\nexpected: %s\nreceived: %s", expectedErr, jsError)
-	}
-}
-
-// Tests that TestJsTrace returns a Javascript Error object with the expected
-// message and stack trace.
-func TestJsTrace(t *testing.T) {
-	err := errors.New("test error")
-	expectedErr := fmt.Sprintf("%+v", err)
-	jsError := JsTrace(err).Get("message").String()
-
-	if jsError != expectedErr {
-		t.Errorf("Failed to get expected error message."+
-			"\nexpected: %s\nreceived: %s", expectedErr, jsError)
-	}
-}
diff --git a/utils/utils.go b/utils/utils.go
deleted file mode 100644
index 8f156761dd4919cfb4e92b93d91acef0253c6901..0000000000000000000000000000000000000000
--- a/utils/utils.go
+++ /dev/null
@@ -1,108 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx foundation                                             //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file.                                                              //
-////////////////////////////////////////////////////////////////////////////////
-
-//go:build js && wasm
-
-package utils
-
-import (
-	"github.com/pkg/errors"
-	jww "github.com/spf13/jwalterweatherman"
-	"syscall/js"
-)
-
-var (
-	// Error is the Javascript Error type. It used to create new Javascript
-	// errors.
-	Error = js.Global().Get("Error")
-
-	// JSON is the Javascript JSON type. It is used to perform JSON operations
-	// on the Javascript layer.
-	JSON = js.Global().Get("JSON")
-
-	// Object is the Javascript Object type. It is used to perform Object
-	// operations on the Javascript layer.
-	Object = js.Global().Get("Object")
-
-	// Promise is the Javascript Promise type. It is used to generate new
-	// promises.
-	Promise = js.Global().Get("Promise")
-
-	// Uint8Array is the Javascript Uint8Array type. It is used to create new
-	// Uint8Array.
-	Uint8Array = js.Global().Get("Uint8Array")
-)
-
-// WrapCB wraps a Javascript function in an object so that it can be called
-// later with only the arguments and without specifying the function name.
-//
-// Panics if m is not a function.
-func WrapCB(parent js.Value, m string) func(args ...any) js.Value {
-	if parent.Get(m).Type() != js.TypeFunction {
-		// Create the error separate from the print so stack trace is printed
-		err := errors.Errorf("Function %q is not of type %s", m, js.TypeFunction)
-		jww.FATAL.Panicf("%+v", err)
-	}
-
-	return func(args ...any) js.Value { return parent.Call(m, args...) }
-}
-
-// PromiseFn converts the Javascript Promise construct into Go.
-//
-// Call resolve with the return of the function on success. Call reject with an
-// error on failure.
-type PromiseFn func(resolve, reject func(args ...any) js.Value)
-
-// CreatePromise creates a Javascript promise to return the value of a blocking
-// Go function to Javascript.
-func CreatePromise(f PromiseFn) any {
-	// Create handler for promise (this will be a Javascript function)
-	var handler js.Func
-	handler = js.FuncOf(func(this js.Value, args []js.Value) any {
-		// Spawn a new go routine to perform the blocking function
-		go func(resolve, reject js.Value) {
-			f(resolve.Invoke, reject.Invoke)
-			go func() { handler.Release() }()
-		}(args[0], args[1])
-
-		return nil
-	})
-
-	// Create and return the Promise object
-	return Promise.New(handler)
-}
-
-// 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 {
-		then <- args
-		return nil
-	})
-	defer thenFunc.Release()
-
-	catch := make(chan []js.Value)
-	defer close(catch)
-	catchFunc := js.FuncOf(func(this js.Value, args []js.Value) any {
-		catch <- args
-		return nil
-	})
-	defer catchFunc.Release()
-
-	awaitable.Call("then", thenFunc).Call("catch", catchFunc)
-
-	select {
-	case result = <-then:
-		return result, nil
-	case err = <-catch:
-		return nil, err
-	}
-}
diff --git a/utils/utils_js.s b/utils/utils_js.s
deleted file mode 100644
index 45c1668a272247a134e6c85508bf5c09f0d7b3f0..0000000000000000000000000000000000000000
--- a/utils/utils_js.s
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "textflag.h"
-
-// Throw enables throwing of Javascript exceptions.
-TEXT ·throw(SB), NOSPLIT, $0
-  CallImport
-  RET
diff --git a/wasm/authenticatedConnection.go b/wasm/authenticatedConnection.go
index 3308a9be32e8321c7d80c7fe5558c794407050b0..61087341cb62c840f4fc765930b16f193536f6d6 100644
--- a/wasm/authenticatedConnection.go
+++ b/wasm/authenticatedConnection.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -73,7 +74,7 @@ func (ac *AuthenticatedConnection) SendE2E(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		sendReport, err := ac.api.SendE2E(mt, payload)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -114,7 +115,7 @@ func (ac *AuthenticatedConnection) RegisterListener(
 	err := ac.api.RegisterListener(args[0].Int(),
 		&listener{utils.WrapCB(args[1], "Hear"), utils.WrapCB(args[1], "Name")})
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -143,7 +144,7 @@ func (c *Cmix) ConnectWithAuthentication(_ js.Value, args []js.Value) any {
 		ac, err := c.api.ConnectWithAuthentication(
 			e2eID, recipientContact, e2eParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(newAuthenticatedConnectionJS(ac))
 		}
diff --git a/wasm/backup.go b/wasm/backup.go
index 9f5e7f6e7b302675ad8a385745dd645473961405..d0f3a885bea45ccef74e8dca1184f644fac99ede 100644
--- a/wasm/backup.go
+++ b/wasm/backup.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -80,7 +81,7 @@ func NewCmixFromBackup(_ js.Value, args []js.Value) any {
 	report, err := bindings.NewCmixFromBackup(ndfJSON, storageDir,
 		backupPassphrase, sessionPassword, backupFileContents)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -110,7 +111,7 @@ func InitializeBackup(_ js.Value, args []js.Value) any {
 	api, err := bindings.InitializeBackup(
 		args[0].Int(), args[1].Int(), args[2].String(), cb)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -138,7 +139,7 @@ func ResumeBackup(_ js.Value, args []js.Value) any {
 	cb := &updateBackupFunc{utils.WrapCB(args[2], "UpdateBackup")}
 	api, err := bindings.ResumeBackup(args[0].Int(), args[1].Int(), cb)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -153,7 +154,7 @@ func ResumeBackup(_ js.Value, args []js.Value) any {
 func (b *Backup) StopBackup(js.Value, []js.Value) any {
 	err := b.api.StopBackup()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/channels.go b/wasm/channels.go
index 307fe5cee304ff580ba1726b8036ce81268cc991..e8fd39e234fe41e2a604da17ce01d68447b76a9c 100644
--- a/wasm/channels.go
+++ b/wasm/channels.go
@@ -14,15 +14,16 @@ import (
 	"encoding/base64"
 	"encoding/json"
 	"errors"
-	"gitlab.com/elixxir/client/v4/channels"
-	"gitlab.com/elixxir/crypto/message"
-	channelsDb "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels"
-	"gitlab.com/xx_network/primitives/id"
 	"sync"
 	"syscall/js"
 
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/client/v4/channels"
+	"gitlab.com/elixxir/crypto/message"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
+	channelsDb "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels"
+	"gitlab.com/xx_network/primitives/id"
 )
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -109,7 +110,7 @@ func (cm *ChannelsManager) GetID(js.Value, []js.Value) any {
 func GenerateChannelIdentity(_ js.Value, args []js.Value) any {
 	pi, err := bindings.GenerateChannelIdentity(args[0].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -144,7 +145,7 @@ func ConstructIdentity(_ js.Value, args []js.Value) any {
 	identity, err := bindings.ConstructIdentity(
 		utils.CopyBytesToGo(args[0]), args[1].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -167,7 +168,7 @@ func constructIdentity(_ js.Value, args []js.Value) any {
 	identity, err := bindings.ConstructIdentity(
 		utils.CopyBytesToGo(args[0]), args[1].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -191,7 +192,7 @@ func ImportPrivateIdentity(_ js.Value, args []js.Value) any {
 
 	pi, err := bindings.ImportPrivateIdentity(password, data)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -212,7 +213,7 @@ func GetPublicChannelIdentity(_ js.Value, args []js.Value) any {
 	marshaledPublic := utils.CopyBytesToGo(args[0])
 	pi, err := bindings.GetPublicChannelIdentity(marshaledPublic)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -236,7 +237,7 @@ func GetPublicChannelIdentityFromPrivate(_ js.Value, args []js.Value) any {
 	identity, err :=
 		bindings.GetPublicChannelIdentityFromPrivate(marshaledPrivate)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -276,7 +277,7 @@ func NewChannelsManager(_ js.Value, args []js.Value) any {
 	cm, err := bindings.NewChannelsManager(
 		cmixId, privateIdentity, extensionBuilderIDsJSON, em)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -307,7 +308,7 @@ func LoadChannelsManager(_ js.Value, args []js.Value) any {
 	em := newEventModelBuilder(args[2])
 	cm, err := bindings.LoadChannelsManager(args[0].Int(), args[1].String(), em)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -371,7 +372,7 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any {
 
 	cipher, err := bindings.GetChannelDbCipherTrackerFromID(cipherID)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 	}
 
 	return newChannelsManagerWithIndexedDb(cmixID, wasmJsPath, privateIdentity,
@@ -461,7 +462,7 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string,
 		cm, err := bindings.NewChannelsManagerGoEventModel(
 			cmixID, privateIdentity, extensionBuilderIDsJSON, model)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(newChannelsManagerJS(cm))
 		}
@@ -519,7 +520,7 @@ func LoadChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any {
 
 	cipher, err := bindings.GetChannelDbCipherTrackerFromID(cipherID)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 	}
 
 	return loadChannelsManagerWithIndexedDb(cmixID, wasmJsPath, storageTag,
@@ -598,7 +599,7 @@ func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string,
 		cm, err := bindings.LoadChannelsManagerGoEventModel(
 			cmixID, storageTag, model, nil)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(newChannelsManagerJS(cm))
 		}
@@ -624,7 +625,7 @@ func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string,
 func DecodePublicURL(_ js.Value, args []js.Value) any {
 	c, err := bindings.DecodePublicURL(args[0].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -646,7 +647,7 @@ func DecodePublicURL(_ js.Value, args []js.Value) any {
 func DecodePrivateURL(_ js.Value, args []js.Value) any {
 	c, err := bindings.DecodePrivateURL(args[0].String(), args[1].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -677,7 +678,7 @@ func DecodePrivateURL(_ js.Value, args []js.Value) any {
 func GetChannelJSON(_ js.Value, args []js.Value) any {
 	c, err := bindings.GetChannelJSON(args[0].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -700,7 +701,7 @@ func GetChannelJSON(_ js.Value, args []js.Value) any {
 func GetChannelInfo(_ js.Value, args []js.Value) any {
 	ci, err := bindings.GetChannelInfo(args[0].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -748,7 +749,7 @@ func (cm *ChannelsManager) GenerateChannel(_ js.Value, args []js.Value) any {
 		prettyPrint, err :=
 			cm.api.GenerateChannel(name, description, privacyLevel)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(prettyPrint)
 		}
@@ -778,7 +779,7 @@ func (cm *ChannelsManager) JoinChannel(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		ci, err := cm.api.JoinChannel(channelPretty)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(ci))
 		}
@@ -802,7 +803,7 @@ func (cm *ChannelsManager) LeaveChannel(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		err := cm.api.LeaveChannel(marshalledChanId)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve()
 		}
@@ -827,7 +828,7 @@ func (cm *ChannelsManager) ReplayChannel(_ js.Value, args []js.Value) any {
 
 	err := cm.api.ReplayChannel(marshalledChanId)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -849,7 +850,7 @@ func (cm *ChannelsManager) ReplayChannel(_ js.Value, args []js.Value) any {
 func (cm *ChannelsManager) GetChannels(js.Value, []js.Value) any {
 	channelList, err := cm.api.GetChannels()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -868,7 +869,7 @@ func (cm *ChannelsManager) EnableDirectMessages(_ js.Value, args []js.Value) any
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 	err := cm.api.EnableDirectMessages(marshalledChanId)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return nil
@@ -886,7 +887,7 @@ func (cm *ChannelsManager) DisableDirectMessages(_ js.Value, args []js.Value) an
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 	err := cm.api.DisableDirectMessages(marshalledChanId)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return nil
@@ -904,7 +905,7 @@ func (cm *ChannelsManager) AreDMsEnabled(_ js.Value, args []js.Value) any {
 	marshalledChanId := utils.CopyBytesToGo(args[0])
 	enabled, err := cm.api.AreDMsEnabled(marshalledChanId)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return false
 	}
 	return enabled
@@ -956,7 +957,7 @@ func (cm *ChannelsManager) GetShareURL(_ js.Value, args []js.Value) any {
 
 	su, err := cm.api.GetShareURL(cmixID, host, maxUses, marshalledChanId)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -982,7 +983,7 @@ func (cm *ChannelsManager) GetShareURL(_ js.Value, args []js.Value) any {
 func GetShareUrlType(_ js.Value, args []js.Value) any {
 	level, err := bindings.GetShareUrlType(args[0].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1042,7 +1043,7 @@ func (cm *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any {
 		sendReport, err := cm.api.SendGeneric(marshalledChanId, messageType,
 			msg, leaseTimeMS, tracked, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -1084,7 +1085,7 @@ func (cm *ChannelsManager) SendMessage(_ js.Value, args []js.Value) any {
 		sendReport, err := cm.api.SendMessage(
 			marshalledChanId, msg, leaseTimeMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -1134,7 +1135,7 @@ func (cm *ChannelsManager) SendReply(_ js.Value, args []js.Value) any {
 		sendReport, err := cm.api.SendReply(marshalledChanId, msg,
 			messageToReactTo, leaseTimeMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -1182,7 +1183,7 @@ func (cm *ChannelsManager) SendReaction(_ js.Value, args []js.Value) any {
 		sendReport, err := cm.api.SendReaction(marshalledChanId, reaction,
 			messageToReactTo, leaseTimeMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -1239,7 +1240,7 @@ func (cm *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any {
 		sendReport, err := cm.api.SendAdminGeneric(marshalledChanId,
 			messageType, msg, leaseTimeMS, tracked, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -1278,7 +1279,7 @@ func (cm *ChannelsManager) DeleteMessage(_ js.Value, args []js.Value) any {
 		sendReport, err := cm.api.DeleteMessage(
 			channelIdBytes, targetMessageIdBytes, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -1320,7 +1321,7 @@ func (cm *ChannelsManager) PinMessage(_ js.Value, args []js.Value) any {
 		sendReport, err := cm.api.PinMessage(channelIdBytes,
 			targetMessageIdBytes, undoAction, validUntilMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -1361,7 +1362,7 @@ func (cm *ChannelsManager) MuteUser(_ js.Value, args []js.Value) any {
 		sendReport, err := cm.api.MuteUser(channelIdBytes, mutedUserPubKeyBytes,
 			undoAction, validUntilMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -1383,7 +1384,7 @@ func (cm *ChannelsManager) MuteUser(_ js.Value, args []js.Value) any {
 func (cm *ChannelsManager) GetIdentity(js.Value, []js.Value) any {
 	i, err := cm.api.GetIdentity()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1402,7 +1403,7 @@ func (cm *ChannelsManager) GetIdentity(js.Value, []js.Value) any {
 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)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1431,7 +1432,7 @@ func (cm *ChannelsManager) GetStorageTag(js.Value, []js.Value) any {
 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)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1449,7 +1450,7 @@ func (cm *ChannelsManager) SetNickname(_ js.Value, args []js.Value) any {
 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)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1468,7 +1469,7 @@ func (cm *ChannelsManager) DeleteNickname(_ js.Value, args []js.Value) any {
 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)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1490,7 +1491,7 @@ func (cm *ChannelsManager) GetNickname(_ js.Value, args []js.Value) any {
 func IsNicknameValid(_ js.Value, args []js.Value) any {
 	err := bindings.IsNicknameValid(args[0].String())
 	if err != nil {
-		return utils.JsError(err)
+		return exception.NewError(err)
 	}
 
 	return nil
@@ -1510,7 +1511,7 @@ func (cm *ChannelsManager) Muted(_ js.Value, args []js.Value) any {
 
 	muted, err := cm.api.Muted(channelIDBytes)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1536,7 +1537,7 @@ 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)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1559,7 +1560,7 @@ func (cm *ChannelsManager) GetMutedUsers(_ js.Value, args []js.Value) any {
 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)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1596,7 +1597,7 @@ func (cm *ChannelsManager) ExportChannelAdminKey(_ js.Value, args []js.Value) an
 	pk, err := cm.api.ExportChannelAdminKey(
 		utils.CopyBytesToGo(args[0]), args[1].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return utils.CopyBytesToJS(pk)
@@ -1630,7 +1631,7 @@ func (cm *ChannelsManager) VerifyChannelAdminKey(_ js.Value, args []js.Value) an
 	valid, err := cm.api.VerifyChannelAdminKey(
 		channelID, encryptionPassword, encryptedPrivKey)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1663,7 +1664,7 @@ func (cm *ChannelsManager) ImportChannelAdminKey(_ js.Value, args []js.Value) an
 	err := cm.api.ImportChannelAdminKey(
 		channelID, encryptionPassword, encryptedPrivKey)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1684,7 +1685,7 @@ func (cm *ChannelsManager) ImportChannelAdminKey(_ js.Value, args []js.Value) an
 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)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1714,7 +1715,7 @@ type channelMessageReceptionCallback struct {
 func (cmrCB *channelMessageReceptionCallback) Callback(
 	receivedChannelMessageReport []byte, err error) int {
 	uuid := cmrCB.callback(
-		utils.CopyBytesToJS(receivedChannelMessageReport), utils.JsTrace(err))
+		utils.CopyBytesToJS(receivedChannelMessageReport), exception.NewTrace(err))
 
 	return uuid.Int()
 }
@@ -1755,7 +1756,7 @@ func (cm *ChannelsManager) RegisterReceiveHandler(_ js.Value, args []js.Value) a
 	err := cm.api.RegisterReceiveHandler(
 		messageType, listenerCb, name, userSpace, adminSpace, mutedSpace)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1787,7 +1788,7 @@ func GetNoMessageErr(js.Value, []js.Value) any {
 // Returns
 //   - True if the error contains channels.NoMessageErr (boolean).
 func CheckNoMessageErr(_ js.Value, args []js.Value) any {
-	return bindings.CheckNoMessageErr(utils.JsErrorToJson(args[0]))
+	return bindings.CheckNoMessageErr(js.Error{Value: args[0]}.Error())
 }
 
 // eventModelBuilder adheres to the [bindings.EventModelBuilder] interface.
@@ -2182,7 +2183,7 @@ func NewChannelsDatabaseCipher(_ js.Value, args []js.Value) any {
 	cipher, err := bindings.NewChannelsDatabaseCipher(
 		cmixId, password, plaintTextBlockSize)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -2212,7 +2213,7 @@ func (c *ChannelDbCipher) GetID(js.Value, []js.Value) any {
 func (c *ChannelDbCipher) Encrypt(_ js.Value, args []js.Value) any {
 	ciphertext, err := c.api.Encrypt(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -2233,7 +2234,7 @@ func (c *ChannelDbCipher) Encrypt(_ js.Value, args []js.Value) any {
 func (c *ChannelDbCipher) Decrypt(_ js.Value, args []js.Value) any {
 	plaintext, err := c.api.Decrypt(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -2248,7 +2249,7 @@ func (c *ChannelDbCipher) Decrypt(_ js.Value, args []js.Value) any {
 func (c *ChannelDbCipher) MarshalJSON(js.Value, []js.Value) any {
 	data, err := c.api.MarshalJSON()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -2269,7 +2270,7 @@ func (c *ChannelDbCipher) MarshalJSON(js.Value, []js.Value) any {
 func (c *ChannelDbCipher) UnmarshalJSON(_ js.Value, args []js.Value) any {
 	err := c.api.UnmarshalJSON(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return nil
diff --git a/wasm/channelsFileTransfer.go b/wasm/channelsFileTransfer.go
index 5155e4ad4668bef0f3ad52f52efec748e7dbb0ff..2a76200423e1ac2aefb94a90857e8c70dc7777c1 100644
--- a/wasm/channelsFileTransfer.go
+++ b/wasm/channelsFileTransfer.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -67,7 +68,7 @@ func InitChannelsFileTransfer(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		cft, err := bindings.InitChannelsFileTransfer(e2eID, paramsJson)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(newChannelsFileTransferJS(cft))
 		}
@@ -164,7 +165,7 @@ func (cft *ChannelsFileTransfer) Upload(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		fileID, err := cft.api.Upload(fileData, retry, progressCB, period)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(fileID))
 		}
@@ -211,7 +212,7 @@ func (cft *ChannelsFileTransfer) Send(_ js.Value, args []js.Value) any {
 		fileID, err := cft.api.Send(channelIdBytes, fileLinkJSON, fileName,
 			fileType, preview, validUntilMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(fileID))
 		}
@@ -264,7 +265,7 @@ func (cft *ChannelsFileTransfer) RegisterSentProgressCallback(
 		err := cft.api.RegisterSentProgressCallback(
 			fileIDBytes, progressCB, periodMS)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve()
 		}
@@ -305,7 +306,7 @@ func (cft *ChannelsFileTransfer) RetryUpload(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		err := cft.api.RetryUpload(fileIDBytes, progressCB, periodMS)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve()
 		}
@@ -334,7 +335,7 @@ func (cft *ChannelsFileTransfer) CloseSend(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		err := cft.api.CloseSend(fileIDBytes)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve()
 		}
@@ -386,7 +387,7 @@ func (cft *ChannelsFileTransfer) Download(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		fileID, err := cft.api.Download(fileInfoJSON, progressCB, periodMS)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(fileID))
 		}
@@ -438,7 +439,7 @@ func (cft *ChannelsFileTransfer) RegisterReceivedProgressCallback(
 		err := cft.api.RegisterReceivedProgressCallback(
 			fileIDBytes, progressCB, periodMS)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve()
 		}
@@ -490,7 +491,7 @@ type ftSentCallback struct {
 func (fsc *ftSentCallback) Callback(
 	payload []byte, t *bindings.ChFilePartTracker, err error) {
 	fsc.callback(utils.CopyBytesToJS(payload), newChFilePartTrackerJS(t),
-		utils.JsTrace(err))
+		exception.NewTrace(err))
 }
 
 // ftReceivedCallback wraps Javascript callbacks to adhere to the
@@ -518,7 +519,7 @@ type ftReceivedCallback struct {
 func (frc *ftReceivedCallback) Callback(
 	payload []byte, t *bindings.ChFilePartTracker, err error) {
 	frc.callback(utils.CopyBytesToJS(payload), newChFilePartTrackerJS(t),
-		utils.JsTrace(err))
+		exception.NewTrace(err))
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/wasm/channels_test.go b/wasm/channels_test.go
index 028e6cbf305e46bc87f398abca1a93918e1f3669..1b4d9eb555177951ea66e9fb81ed7420418f2b22 100644
--- a/wasm/channels_test.go
+++ b/wasm/channels_test.go
@@ -12,7 +12,7 @@ package wasm
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
 	"gitlab.com/elixxir/crypto/channel"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/xx_network/crypto/csprng"
 	"reflect"
 	"syscall/js"
diff --git a/wasm/cmix.go b/wasm/cmix.go
index e3430f4cf4b489ad7480ab53522fac2631c7cbce..eb031d18fc25160309969863e4a222194f650ea1 100644
--- a/wasm/cmix.go
+++ b/wasm/cmix.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -98,7 +99,7 @@ func NewCmix(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		err := bindings.NewCmix(ndfJSON, storageDir, password, registrationCode)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve()
 		}
@@ -133,7 +134,7 @@ func LoadCmix(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		net, err := bindings.LoadCmix(storageDir, password, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(newCmixJS(net))
 		}
@@ -172,7 +173,7 @@ func (c *Cmix) EKVGet(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		val, err := c.api.EKVGet(key)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(val))
 		}
@@ -197,7 +198,7 @@ func (c *Cmix) EKVSet(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		err := c.api.EKVSet(key, val)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(nil)
 		}
diff --git a/wasm/connect.go b/wasm/connect.go
index bfb95a6d882f808277a856dfbda9937c3bb3d687..279b98512e9b6ad91b62f0b6428a4d510b8c1f78 100644
--- a/wasm/connect.go
+++ b/wasm/connect.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -68,7 +69,7 @@ func (c *Cmix) Connect(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		api, err := c.api.Connect(e2eID, recipientContact, e2eParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(newConnectJS(api))
 		}
@@ -95,7 +96,7 @@ func (c *Connection) SendE2E(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		sendReport, err := c.api.SendE2E(e2eID, payload)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -111,7 +112,7 @@ func (c *Connection) SendE2E(_ js.Value, args []js.Value) any {
 func (c *Connection) Close(js.Value, []js.Value) any {
 	err := c.api.Close()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -158,7 +159,7 @@ func (c *Connection) RegisterListener(_ js.Value, args []js.Value) any {
 	err := c.api.RegisterListener(args[0].Int(),
 		&listener{utils.WrapCB(args[1], "Hear"), utils.WrapCB(args[1], "Name")})
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/delivery.go b/wasm/delivery.go
index 327f15223426bf3ac19c4d001806b8e69abdfb9e..43c56a69d20c2da68228d2c701505c8938c86654 100644
--- a/wasm/delivery.go
+++ b/wasm/delivery.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -87,7 +88,7 @@ func (c *Cmix) WaitForRoundResult(_ js.Value, args []js.Value) any {
 
 	err := c.api.WaitForRoundResult(roundList, mdc, args[2].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/dm.go b/wasm/dm.go
index 50aebb08a1ac9bdbce7ba5d7e53c2f0591a24577..5503799fc7bd48be7ddc465202b6a9b4079c30fb 100644
--- a/wasm/dm.go
+++ b/wasm/dm.go
@@ -20,8 +20,9 @@ import (
 	"gitlab.com/elixxir/client/v4/bindings"
 	"gitlab.com/elixxir/client/v4/dm"
 	"gitlab.com/elixxir/crypto/codename"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	indexDB "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/dm"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
 )
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -92,7 +93,7 @@ func NewDMClient(_ js.Value, args []js.Value) any {
 
 	cm, err := bindings.NewDMClient(args[0].Int(), privateIdentity, em)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -138,7 +139,7 @@ func NewDMClientWithIndexedDb(_ js.Value, args []js.Value) any {
 
 	cipher, err := bindings.GetDMDbCipherTrackerFromID(cipherID)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 	}
 
 	return newDMClientWithIndexedDb(
@@ -196,19 +197,19 @@ func newDMClientWithIndexedDb(cmixID int, wasmJsPath string,
 
 		pi, err := codename.UnmarshalPrivateIdentity(privateIdentity)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		}
 		dmPath := base64.RawStdEncoding.EncodeToString(pi.PubKey[:])
 		model, err := indexDB.NewWASMEventModel(
 			dmPath, wasmJsPath, cipher, messageReceivedCB)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		}
 
 		cm, err := bindings.NewDMClientWithGoEventModel(
 			cmixID, privateIdentity, model)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(newDMClientJS(cm))
 		}
@@ -259,7 +260,7 @@ func (dmc *DMClient) GetIdentity(js.Value, []js.Value) any {
 func (dmc *DMClient) ExportPrivateIdentity(_ js.Value, args []js.Value) any {
 	i, err := dmc.api.ExportPrivateIdentity(args[0].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -275,7 +276,7 @@ func (dmc *DMClient) ExportPrivateIdentity(_ js.Value, args []js.Value) any {
 func (dmc *DMClient) GetNickname(_ js.Value, _ []js.Value) any {
 	nickname, err := dmc.api.GetNickname()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -359,7 +360,7 @@ func (dmc *DMClient) SendText(_ js.Value, args []js.Value) any {
 		sendReport, err := dmc.api.SendText(partnerPubKeyBytes, partnerToken,
 			message, leaseTimeMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -417,7 +418,7 @@ func (dmc *DMClient) SendReply(_ js.Value, args []js.Value) any {
 		sendReport, err := dmc.api.SendReply(partnerPubKeyBytes, partnerToken,
 			replyMessage, replyToBytes, leaseTimeMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -464,7 +465,7 @@ func (dmc *DMClient) SendReaction(_ js.Value, args []js.Value) any {
 		sendReport, err := dmc.api.SendReaction(partnerPubKeyBytes,
 			partnerToken, reaction, reactToBytes, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -515,7 +516,7 @@ func (dmc *DMClient) Send(_ js.Value, args []js.Value) any {
 		sendReport, err := dmc.api.Send(partnerPubKeyBytes, partnerToken,
 			messageType, plaintext, leaseTimeMS, cmixParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -578,7 +579,7 @@ func (dmc *DMClient) GetShareURL(_ js.Value, args []js.Value) any {
 	host := args[0].String()
 	urlReport, err := dmc.api.GetShareURL(host)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -598,7 +599,7 @@ func DecodeDMShareURL(_ js.Value, args []js.Value) any {
 	url := args[0].String()
 	report, err := bindings.DecodeDMShareURL(url)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -629,7 +630,7 @@ func (cmrCB *dmReceptionCallback) Callback(
 	receivedChannelMessageReport []byte, err error) int {
 	uuid := cmrCB.callback(
 		utils.CopyBytesToJS(receivedChannelMessageReport),
-		utils.JsTrace(err))
+		exception.NewTrace(err))
 
 	return uuid.Int()
 }
@@ -970,7 +971,7 @@ func NewDMsDatabaseCipher(_ js.Value, args []js.Value) any {
 	cipher, err := bindings.NewDMsDatabaseCipher(
 		cmixId, password, plaintTextBlockSize)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1000,7 +1001,7 @@ func (c *DMDbCipher) GetID(js.Value, []js.Value) any {
 func (c *DMDbCipher) Encrypt(_ js.Value, args []js.Value) any {
 	ciphertext, err := c.api.Encrypt(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1021,7 +1022,7 @@ func (c *DMDbCipher) Encrypt(_ js.Value, args []js.Value) any {
 func (c *DMDbCipher) Decrypt(_ js.Value, args []js.Value) any {
 	plaintext, err := c.api.Decrypt(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1036,7 +1037,7 @@ func (c *DMDbCipher) Decrypt(_ js.Value, args []js.Value) any {
 func (c *DMDbCipher) MarshalJSON(js.Value, []js.Value) any {
 	data, err := c.api.MarshalJSON()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -1058,7 +1059,7 @@ func (c *DMDbCipher) MarshalJSON(js.Value, []js.Value) any {
 func (c *DMDbCipher) UnmarshalJSON(_ js.Value, args []js.Value) any {
 	err := c.api.UnmarshalJSON(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return nil
diff --git a/wasm/dummy.go b/wasm/dummy.go
index 82b9128ce52cb3521056da6a77358bb44a4a5e5c..b0fa6a82bad4f8e28290663eff285d002f10cafb 100644
--- a/wasm/dummy.go
+++ b/wasm/dummy.go
@@ -11,7 +11,7 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
 	"syscall/js"
 )
 
@@ -58,7 +58,7 @@ func NewDummyTrafficManager(_ js.Value, args []js.Value) any {
 	dt, err := bindings.NewDummyTrafficManager(
 		args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -80,7 +80,7 @@ func NewDummyTrafficManager(_ js.Value, args []js.Value) any {
 func (dt *DummyTraffic) Pause(js.Value, []js.Value) any {
 	err := dt.api.Pause()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -103,7 +103,7 @@ func (dt *DummyTraffic) Pause(js.Value, []js.Value) any {
 func (dt *DummyTraffic) Start(js.Value, []js.Value) any {
 	err := dt.api.Start()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/e2e.go b/wasm/e2e.go
index 8d8f4ce15fa0c47f71c3bbbeccdf9484a4ccde39..5f3debbca3bb52f2b5e594942eaed3c96bcabd5a 100644
--- a/wasm/e2e.go
+++ b/wasm/e2e.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -99,7 +100,7 @@ func Login(_ js.Value, args []js.Value) any {
 	newE2E, err := bindings.Login(
 		args[0].Int(), callbacks, identity, e2eParamsJSON)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -129,7 +130,7 @@ func LoginEphemeral(_ js.Value, args []js.Value) any {
 	newE2E, err := bindings.LoginEphemeral(
 		args[0].Int(), callbacks, identity, e2eParamsJSON)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -171,7 +172,7 @@ func (e *E2e) GetUdCertFromNdf(js.Value, []js.Value) any {
 func (e *E2e) GetUdContactFromNdf(js.Value, []js.Value) any {
 	b, err := e.api.GetUdContactFromNdf()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/e2eAuth.go b/wasm/e2eAuth.go
index eb69ef75cd17d26b22715d0eba08bf6b5f0fc02a..351ed123db2b69c315ceb61bcd5885146149e3dd 100644
--- a/wasm/e2eAuth.go
+++ b/wasm/e2eAuth.go
@@ -10,7 +10,8 @@
 package wasm
 
 import (
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -46,7 +47,7 @@ func (e *E2e) Request(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		rid, err := e.api.Request(partnerContact, factsListJson)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(rid)
 		}
@@ -83,7 +84,7 @@ func (e *E2e) Confirm(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		rid, err := e.api.Confirm(partnerContact)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(rid)
 		}
@@ -118,7 +119,7 @@ func (e *E2e) Reset(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		rid, err := e.api.Reset(partnerContact)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(rid)
 		}
@@ -147,7 +148,7 @@ func (e *E2e) ReplayConfirm(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		rid, err := e.api.ReplayConfirm(partnerContact)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(rid)
 		}
@@ -174,7 +175,7 @@ func (e *E2e) DeleteRequest(_ js.Value, args []js.Value) any {
 	partnerContact := utils.CopyBytesToGo(args[0])
 	err := e.api.DeleteRequest(partnerContact)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -188,7 +189,7 @@ func (e *E2e) DeleteRequest(_ js.Value, args []js.Value) any {
 func (e *E2e) DeleteAllRequests(js.Value, []js.Value) any {
 	err := e.api.DeleteAllRequests()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -202,7 +203,7 @@ func (e *E2e) DeleteAllRequests(js.Value, []js.Value) any {
 func (e *E2e) DeleteSentRequests(js.Value, []js.Value) any {
 	err := e.api.DeleteSentRequests()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -216,7 +217,7 @@ func (e *E2e) DeleteSentRequests(js.Value, []js.Value) any {
 func (e *E2e) DeleteReceiveRequests(js.Value, []js.Value) any {
 	err := e.api.DeleteReceiveRequests()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -235,7 +236,7 @@ func (e *E2e) GetReceivedRequest(_ js.Value, args []js.Value) any {
 	partnerContact := utils.CopyBytesToGo(args[0])
 	c, err := e.api.GetReceivedRequest(partnerContact)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -260,7 +261,7 @@ func (e *E2e) VerifyOwnership(_ js.Value, args []js.Value) any {
 	isValid, err := e.api.VerifyOwnership(
 		receivedContact, verifiedContact, args[2].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -282,7 +283,7 @@ func (e *E2e) AddPartnerCallback(_ js.Value, args []js.Value) any {
 	callbacks := newAuthCallbacks(args[1])
 	err := e.api.AddPartnerCallback(partnerID, callbacks)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -301,7 +302,7 @@ func (e *E2e) DeletePartnerCallback(_ js.Value, args []js.Value) any {
 	partnerID := utils.CopyBytesToGo(args[0])
 	err := e.api.DeletePartnerCallback(partnerID)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/e2eHandler.go b/wasm/e2eHandler.go
index bff44e6aa48567e5c6afae5dca439b6fa93a6fa1..7f3b5966e886b7e77752da24a03f64ac369b01be 100644
--- a/wasm/e2eHandler.go
+++ b/wasm/e2eHandler.go
@@ -10,7 +10,8 @@
 package wasm
 
 import (
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -32,7 +33,7 @@ func (e *E2e) GetReceptionID(js.Value, []js.Value) any {
 func (e *E2e) DeleteContact(_ js.Value, args []js.Value) any {
 	err := e.api.DeleteContact(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return nil
@@ -47,7 +48,7 @@ func (e *E2e) DeleteContact(_ js.Value, args []js.Value) any {
 func (e *E2e) GetAllPartnerIDs(js.Value, []js.Value) any {
 	partnerIDs, err := e.api.GetAllPartnerIDs()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return utils.CopyBytesToJS(partnerIDs)
@@ -100,7 +101,7 @@ func (e *E2e) FirstPartitionSize(js.Value, []js.Value) any {
 func (e *E2e) GetHistoricalDHPrivkey(js.Value, []js.Value) any {
 	privKey, err := e.api.GetHistoricalDHPrivkey()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return utils.CopyBytesToJS(privKey)
@@ -115,7 +116,7 @@ func (e *E2e) GetHistoricalDHPrivkey(js.Value, []js.Value) any {
 func (e *E2e) GetHistoricalDHPubkey(js.Value, []js.Value) any {
 	pubKey, err := e.api.GetHistoricalDHPubkey()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return utils.CopyBytesToJS(pubKey)
@@ -133,7 +134,7 @@ func (e *E2e) GetHistoricalDHPubkey(js.Value, []js.Value) any {
 func (e *E2e) HasAuthenticatedChannel(_ js.Value, args []js.Value) any {
 	exists, err := e.api.HasAuthenticatedChannel(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 	return exists
@@ -149,7 +150,7 @@ func (e *E2e) HasAuthenticatedChannel(_ js.Value, args []js.Value) any {
 func (e *E2e) RemoveService(_ js.Value, args []js.Value) any {
 	err := e.api.RemoveService(args[0].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -178,7 +179,7 @@ func (e *E2e) SendE2E(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		sendReport, err := e.api.SendE2E(mt, recipientId, payload, e2eParams)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -236,7 +237,7 @@ func (e *E2e) AddService(_ js.Value, args []js.Value) any {
 
 	err := e.api.AddService(args[0].String(), p)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -261,7 +262,7 @@ func (e *E2e) RegisterListener(_ js.Value, args []js.Value) any {
 
 	err := e.api.RegisterListener(recipientId, args[1].Int(), l)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/emoji.go b/wasm/emoji.go
index fbde2b5717a4c745fc7f7339d96f157703138cad..fd64418cdc7c14ac823c3115178d835efc88faf2 100644
--- a/wasm/emoji.go
+++ b/wasm/emoji.go
@@ -13,7 +13,8 @@ import (
 	"syscall/js"
 
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 )
 
 // SupportedEmojis returns a list of emojis that are supported by the backend.
@@ -56,7 +57,7 @@ import (
 func SupportedEmojis(js.Value, []js.Value) any {
 	data, err := bindings.SupportedEmojis()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -101,7 +102,7 @@ func SupportedEmojis(js.Value, []js.Value) any {
 func SupportedEmojisMap(js.Value, []js.Value) any {
 	data, err := bindings.SupportedEmojisMap()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -121,7 +122,7 @@ func SupportedEmojisMap(js.Value, []js.Value) any {
 func ValidateReaction(_ js.Value, args []js.Value) any {
 	err := bindings.ValidateReaction(args[0].String())
 	if err != nil {
-		return utils.JsError(err)
+		return exception.NewError(err)
 	}
 
 	return nil
diff --git a/wasm/errors.go b/wasm/errors.go
index 9299c60e0d9c02e81a1ea54755c26d7be62b87bf..baf9e8b095afed9b291bdfc9c793eaf3d70bea7f 100644
--- a/wasm/errors.go
+++ b/wasm/errors.go
@@ -11,7 +11,7 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
 	"syscall/js"
 )
 
@@ -53,7 +53,7 @@ func CreateUserFriendlyErrorMessage(_ js.Value, args []js.Value) any {
 func UpdateCommonErrors(_ js.Value, args []js.Value) any {
 	err := bindings.UpdateCommonErrors(args[0].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/fileTransfer.go b/wasm/fileTransfer.go
index 0083a98a78b2544f90b96623b88157b9dd70acb2..e91a8837cec438f4644e48407fdf2924a81eb1bc 100644
--- a/wasm/fileTransfer.go
+++ b/wasm/fileTransfer.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -84,7 +85,7 @@ type fileTransferSentProgressCallback struct {
 func (spc *fileTransferSentProgressCallback) Callback(
 	payload []byte, t *bindings.FilePartTracker, err error) {
 	spc.callback(utils.CopyBytesToJS(payload), newFilePartTrackerJS(t),
-		utils.JsTrace(err))
+		exception.NewTrace(err))
 }
 
 // fileTransferReceiveProgressCallback wraps Javascript callbacks to adhere to
@@ -105,7 +106,7 @@ type fileTransferReceiveProgressCallback struct {
 func (rpc *fileTransferReceiveProgressCallback) Callback(
 	payload []byte, t *bindings.FilePartTracker, err error) {
 	rpc.callback(utils.CopyBytesToJS(payload), newFilePartTrackerJS(t),
-		utils.JsTrace(err))
+		exception.NewTrace(err))
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -133,7 +134,7 @@ func InitFileTransfer(_ js.Value, args []js.Value) any {
 	api, err := bindings.InitFileTransfer(
 		args[0].Int(), rfc, e2eFileTransferParamsJson, fileTransferParamsJson)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -163,7 +164,7 @@ func (f *FileTransfer) Send(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		ftID, err := f.api.Send(payload, recipientID, retry, spc, args[4].Int())
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(ftID))
 		}
@@ -190,7 +191,7 @@ func (f *FileTransfer) Send(_ js.Value, args []js.Value) any {
 func (f *FileTransfer) Receive(_ js.Value, args []js.Value) any {
 	file, err := f.api.Receive(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -212,7 +213,7 @@ func (f *FileTransfer) Receive(_ js.Value, args []js.Value) any {
 func (f *FileTransfer) CloseSend(_ js.Value, args []js.Value) any {
 	err := f.api.CloseSend(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -245,7 +246,7 @@ func (f *FileTransfer) RegisterSentProgressCallback(
 
 	err := f.api.RegisterSentProgressCallback(tidBytes, spc, args[2].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -274,7 +275,7 @@ func (f *FileTransfer) RegisterReceivedProgressCallback(
 	err := f.api.RegisterReceivedProgressCallback(
 		tidBytes, rpc, args[2].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/follow.go b/wasm/follow.go
index dbff9722411ddac19999b28b137739ec31279a45..b215bf5471ca7d5028a7d84d6128c61394e472e4 100644
--- a/wasm/follow.go
+++ b/wasm/follow.go
@@ -10,8 +10,9 @@
 package wasm
 
 import (
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/elixxir/xxdk-wasm/storage"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
 	"syscall/js"
 )
 
@@ -57,7 +58,7 @@ import (
 func (c *Cmix) StartNetworkFollower(_ js.Value, args []js.Value) any {
 	err := c.api.StartNetworkFollower(args[0].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -76,7 +77,7 @@ func (c *Cmix) StartNetworkFollower(_ js.Value, args []js.Value) any {
 func (c *Cmix) StopNetworkFollower(js.Value, []js.Value) any {
 	err := c.api.StopNetworkFollower()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -165,7 +166,7 @@ func (c *Cmix) NetworkFollowerStatus(js.Value, []js.Value) any {
 func (c *Cmix) GetNodeRegistrationStatus(js.Value, []js.Value) any {
 	b, err := c.api.GetNodeRegistrationStatus()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -186,7 +187,7 @@ func (c *Cmix) GetNodeRegistrationStatus(js.Value, []js.Value) any {
 func (c *Cmix) IsReady(_ js.Value, args []js.Value) any {
 	isReadyInfo, err := c.api.IsReady(args[0].Float())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -205,7 +206,7 @@ func (c *Cmix) IsReady(_ js.Value, args []js.Value) any {
 func (c *Cmix) PauseNodeRegistrations(_ js.Value, args []js.Value) any {
 	err := c.api.PauseNodeRegistrations(args[0].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -225,7 +226,7 @@ func (c *Cmix) PauseNodeRegistrations(_ js.Value, args []js.Value) any {
 func (c *Cmix) ChangeNumberOfNodeRegistrations(_ js.Value, args []js.Value) any {
 	err := c.api.ChangeNumberOfNodeRegistrations(args[0].Int(), args[1].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -271,7 +272,7 @@ func (c *Cmix) IsHealthy(js.Value, []js.Value) any {
 func (c *Cmix) GetRunningProcesses(js.Value, []js.Value) any {
 	list, err := c.api.GetRunningProcesses()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -377,7 +378,7 @@ type trackServicesCallback struct {
 //	  },
 //	]
 func (tsc *trackServicesCallback) Callback(marshalData []byte, err error) {
-	tsc.callback(utils.CopyBytesToJS(marshalData), utils.JsTrace(err))
+	tsc.callback(utils.CopyBytesToJS(marshalData), exception.NewTrace(err))
 }
 
 // TrackServicesWithIdentity will return via a callback the list of services the
@@ -396,7 +397,7 @@ func (c *Cmix) TrackServicesWithIdentity(_ js.Value, args []js.Value) any {
 	err := c.api.TrackServicesWithIdentity(args[0].Int(),
 		&trackServicesCallback{utils.WrapCB(args[0], "Callback")})
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/group.go b/wasm/group.go
index f3e7710a9144ba86fd33322b05c44092dd5c89bc..459a07db0cd79815da19f5d86254150f88ad1748 100644
--- a/wasm/group.go
+++ b/wasm/group.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -62,7 +63,7 @@ func NewGroupChat(_ js.Value, args []js.Value) any {
 
 	api, err := bindings.NewGroupChat(args[0].Int(), requestFunc, p)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -93,7 +94,7 @@ func (g *GroupChat) MakeGroup(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		sendReport, err := g.api.MakeGroup(membershipBytes, message, name)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -117,7 +118,7 @@ func (g *GroupChat) ResendRequest(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		sendReport, err := g.api.ResendRequest(groupId)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -139,7 +140,7 @@ func (g *GroupChat) ResendRequest(_ js.Value, args []js.Value) any {
 func (g *GroupChat) JoinGroup(_ js.Value, args []js.Value) any {
 	err := g.api.JoinGroup(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -157,7 +158,7 @@ func (g *GroupChat) JoinGroup(_ js.Value, args []js.Value) any {
 func (g *GroupChat) LeaveGroup(_ js.Value, args []js.Value) any {
 	err := g.api.LeaveGroup(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -187,7 +188,7 @@ func (g *GroupChat) Send(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		sendReport, err := g.api.Send(groupId, message, tag)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -204,7 +205,7 @@ func (g *GroupChat) Send(_ js.Value, args []js.Value) any {
 func (g *GroupChat) GetGroups(js.Value, []js.Value) any {
 	groups, err := g.api.GetGroups()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -224,7 +225,7 @@ func (g *GroupChat) GetGroups(js.Value, []js.Value) any {
 func (g *GroupChat) GetGroup(_ js.Value, args []js.Value) any {
 	grp, err := g.api.GetGroup(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -318,7 +319,7 @@ func (g *Group) GetCreatedMS(js.Value, []js.Value) any {
 func (g *Group) GetMembership(js.Value, []js.Value) any {
 	membership, err := g.api.GetMembership()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -345,7 +346,7 @@ func (g *Group) Serialize(js.Value, []js.Value) any {
 func DeserializeGroup(_ js.Value, args []js.Value) any {
 	grp, err := bindings.DeserializeGroup(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -393,7 +394,7 @@ func (gcp *groupChatProcessor) Process(decryptedMessage, msg,
 	receptionId []byte, ephemeralId, roundId int64, roundURL string, err error) {
 	gcp.process(utils.CopyBytesToJS(decryptedMessage),
 		utils.CopyBytesToJS(msg), utils.CopyBytesToJS(receptionId), ephemeralId,
-		roundId, roundURL, utils.JsTrace(err))
+		roundId, roundURL, exception.NewTrace(err))
 }
 
 // String returns a name identifying this processor. Used for debugging.
diff --git a/wasm/identity.go b/wasm/identity.go
index 4141b1f1b9dc0b6a2cf0f374b428118b19899363..013d2059b31378b2ce2e580723ada3d59fa35697 100644
--- a/wasm/identity.go
+++ b/wasm/identity.go
@@ -12,7 +12,8 @@ package wasm
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
 	"gitlab.com/elixxir/client/v4/xxdk"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -38,7 +39,7 @@ func StoreReceptionIdentity(_ js.Value, args []js.Value) any {
 		args[0].String(), identity, args[2].Int())
 
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -58,7 +59,7 @@ func StoreReceptionIdentity(_ js.Value, args []js.Value) any {
 func LoadReceptionIdentity(_ js.Value, args []js.Value) any {
 	ri, err := bindings.LoadReceptionIdentity(args[0].String(), args[1].Int())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -75,7 +76,7 @@ func (c *Cmix) MakeReceptionIdentity(js.Value, []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		ri, err := c.api.MakeReceptionIdentity()
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(ri))
 		}
@@ -94,7 +95,7 @@ func (c *Cmix) MakeLegacyReceptionIdentity(js.Value, []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		ri, err := c.api.MakeLegacyReceptionIdentity()
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(ri))
 		}
@@ -132,7 +133,7 @@ func GetContactFromReceptionIdentity(_ js.Value, args []js.Value) any {
 	identityJSON := utils.CopyBytesToGo(args[0])
 	identity, err := xxdk.UnmarshalReceptionIdentity(identityJSON)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -150,7 +151,7 @@ func GetContactFromReceptionIdentity(_ js.Value, args []js.Value) any {
 func GetIDFromContact(_ js.Value, args []js.Value) any {
 	cID, err := bindings.GetIDFromContact(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -169,7 +170,7 @@ func GetIDFromContact(_ js.Value, args []js.Value) any {
 func GetPubkeyFromContact(_ js.Value, args []js.Value) any {
 	key, err := bindings.GetPubkeyFromContact([]byte(args[0].String()))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -195,7 +196,7 @@ func SetFactsOnContact(_ js.Value, args []js.Value) any {
 	factListJSON := utils.CopyBytesToGo(args[1])
 	c, err := bindings.SetFactsOnContact(marshaledContact, factListJSON)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -213,7 +214,7 @@ func SetFactsOnContact(_ js.Value, args []js.Value) any {
 func GetFactsFromContact(_ js.Value, args []js.Value) any {
 	fl, err := bindings.GetFactsFromContact(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
diff --git a/wasm/ndf.go b/wasm/ndf.go
index 69441fea2c03e5f369a0e9a76a5936b7e43bf67f..292fe3ecfb42d57a2a7964c03265bdfd7c39d14c 100644
--- a/wasm/ndf.go
+++ b/wasm/ndf.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -34,7 +35,7 @@ func DownloadAndVerifySignedNdfWithUrl(_ js.Value, args []js.Value) any {
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
 		ndf, err := bindings.DownloadAndVerifySignedNdfWithUrl(url, cert)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(ndf))
 		}
diff --git a/wasm/params.go b/wasm/params.go
index 01f307c6c029f1643e674fe7b77db44d4830b2fe..5b8dac2f78656de84be3050705cc4c72415a5ee7 100644
--- a/wasm/params.go
+++ b/wasm/params.go
@@ -11,7 +11,7 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
diff --git a/wasm/restlike.go b/wasm/restlike.go
index 0cf802a32bb0c638859c77d1a32fc609cd2994b8..d56ff586279f292042d2faa7df39d38714273272 100644
--- a/wasm/restlike.go
+++ b/wasm/restlike.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -39,7 +40,7 @@ func RestlikeRequest(_ js.Value, args []js.Value) any {
 		msg, err := bindings.RestlikeRequest(
 			cmixId, connectionID, request, e2eParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(msg))
 		}
@@ -72,7 +73,7 @@ func RestlikeRequestAuth(_ js.Value, args []js.Value) any {
 		msg, err := bindings.RestlikeRequestAuth(
 			cmixId, authConnectionID, request, e2eParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(msg))
 		}
diff --git a/wasm/restlikeSingle.go b/wasm/restlikeSingle.go
index 391e40c01a2711aa630468ae59d06e15b5312bab..7a2e8f8c2828b3c3b91b56e0ba5cce3ed45ef548 100644
--- a/wasm/restlikeSingle.go
+++ b/wasm/restlikeSingle.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -27,7 +28,7 @@ type restlikeCallback struct {
 //   - payload - JSON of [restlike.Message] (Uint8Array).
 //   - err - Returns an error on failure (Error).
 func (rlc *restlikeCallback) Callback(payload []byte, err error) {
-	rlc.callback(utils.CopyBytesToJS(payload), utils.JsTrace(err))
+	rlc.callback(utils.CopyBytesToJS(payload), exception.NewTrace(err))
 }
 
 // RequestRestLike sends a restlike request to a given contact.
@@ -54,7 +55,7 @@ func RequestRestLike(_ js.Value, args []js.Value) any {
 		msg, err := bindings.RequestRestLike(
 			e2eID, recipient, request, paramsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(msg))
 		}
@@ -91,7 +92,7 @@ func AsyncRequestRestLike(_ js.Value, args []js.Value) any {
 		err := bindings.AsyncRequestRestLike(
 			e2eID, recipient, request, paramsJSON, cb)
 		if err != nil {
-			utils.Throw(utils.TypeError, err)
+			exception.ThrowTrace(err)
 		}
 	}()
 
diff --git a/wasm/secrets.go b/wasm/secrets.go
index d310fcbcd4cd7e2593ec6d360274ed5cf9eea48c..4cba18e0495a251eb7a803bafd968c8f16757e50 100644
--- a/wasm/secrets.go
+++ b/wasm/secrets.go
@@ -11,7 +11,7 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
diff --git a/wasm/single.go b/wasm/single.go
index 8198bb80fc58de0b21a045c47b39194efd149cfa..5d6aa92eef53055bf8316f5dfaedea1b81746f97 100644
--- a/wasm/single.go
+++ b/wasm/single.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -49,7 +50,7 @@ func TransmitSingleUse(_ js.Value, args []js.Value) any {
 		sendReport, err := bindings.TransmitSingleUse(
 			e2eID, recipient, tag, payload, paramsJSON, responseCB)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -76,7 +77,7 @@ func Listen(_ js.Value, args []js.Value) any {
 	cb := &singleUseCallback{utils.WrapCB(args[2], "Callback")}
 	api, err := bindings.Listen(args[0].Int(), args[1].String(), cb)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -128,7 +129,7 @@ type singleUseCallback struct {
 //     (Uint8Array).
 //   - err - Returns an error on failure (Error).
 func (suc *singleUseCallback) Callback(callbackReport []byte, err error) {
-	suc.callback(utils.CopyBytesToJS(callbackReport), utils.JsTrace(err))
+	suc.callback(utils.CopyBytesToJS(callbackReport), exception.NewTrace(err))
 }
 
 // singleUseResponse wraps Javascript callbacks to adhere to the
@@ -145,5 +146,5 @@ type singleUseResponse struct {
 //     (Uint8Array).
 //   - err - Returns an error on failure (Error).
 func (sur *singleUseResponse) Callback(responseReport []byte, err error) {
-	sur.callback(utils.CopyBytesToJS(responseReport), utils.JsTrace(err))
+	sur.callback(utils.CopyBytesToJS(responseReport), exception.NewTrace(err))
 }
diff --git a/wasm/timeNow.go b/wasm/timeNow.go
index 627a16b4e344089d782edf435fdcd3225c6c230b..ca3ebe6037161df753d80f7ed08e01c4e3d5b335 100644
--- a/wasm/timeNow.go
+++ b/wasm/timeNow.go
@@ -11,7 +11,7 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
diff --git a/wasm/ud.go b/wasm/ud.go
index 74bc2b11b628a4139040168194af9b6d21009a72..8b69f196b6362c3116551a9f78a0191d549fa571 100644
--- a/wasm/ud.go
+++ b/wasm/ud.go
@@ -11,7 +11,8 @@ package wasm
 
 import (
 	"gitlab.com/elixxir/client/v4/bindings"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"syscall/js"
 )
 
@@ -112,7 +113,7 @@ func NewOrLoadUd(_ js.Value, args []js.Value) any {
 	api, err := bindings.NewOrLoadUd(e2eID, follower, username,
 		registrationValidationSignature, cert, contactFile, address)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -157,7 +158,7 @@ func NewUdManagerFromBackup(_ js.Value, args []js.Value) any {
 		e2eID, follower, cert,
 		contactFile, address)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -182,7 +183,7 @@ func (ud *UserDiscovery) GetFacts(js.Value, []js.Value) any {
 func (ud *UserDiscovery) GetContact(js.Value, []js.Value) any {
 	c, err := ud.api.GetContact()
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -203,7 +204,7 @@ func (ud *UserDiscovery) GetContact(js.Value, []js.Value) any {
 func (ud *UserDiscovery) ConfirmFact(_ js.Value, args []js.Value) any {
 	err := ud.api.ConfirmFact(args[0].String(), args[1].String())
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -228,7 +229,7 @@ func (ud *UserDiscovery) ConfirmFact(_ js.Value, args []js.Value) any {
 func (ud *UserDiscovery) SendRegisterFact(_ js.Value, args []js.Value) any {
 	confirmationID, err := ud.api.SendRegisterFact(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -247,7 +248,7 @@ func (ud *UserDiscovery) SendRegisterFact(_ js.Value, args []js.Value) any {
 func (ud *UserDiscovery) PermanentDeleteAccount(_ js.Value, args []js.Value) any {
 	err := ud.api.PermanentDeleteAccount(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -265,7 +266,7 @@ func (ud *UserDiscovery) PermanentDeleteAccount(_ js.Value, args []js.Value) any
 func (ud *UserDiscovery) RemoveFact(_ js.Value, args []js.Value) any {
 	err := ud.api.RemoveFact(utils.CopyBytesToGo(args[0]))
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 		return nil
 	}
 
@@ -290,7 +291,7 @@ type udLookupCallback struct {
 //     the lookup, or nil if an error occurs (Uint8Array).
 //   - err - Returns an error on failure (Error).
 func (ulc *udLookupCallback) Callback(contactBytes []byte, err error) {
-	ulc.callback(utils.CopyBytesToJS(contactBytes), utils.JsTrace(err))
+	ulc.callback(utils.CopyBytesToJS(contactBytes), exception.NewTrace(err))
 }
 
 // LookupUD returns the public key of the passed ID as known by the user
@@ -322,7 +323,7 @@ func LookupUD(_ js.Value, args []js.Value) any {
 		sendReport, err := bindings.LookupUD(
 			e2eID, udContact, cb, lookupId, singleRequestParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
@@ -357,7 +358,7 @@ type udSearchCallback struct {
 //	  "<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>"
 //	}
 func (usc *udSearchCallback) Callback(contactListJSON []byte, err error) {
-	usc.callback(utils.CopyBytesToJS(contactListJSON), utils.JsTrace(err))
+	usc.callback(utils.CopyBytesToJS(contactListJSON), exception.NewTrace(err))
 }
 
 // SearchUD searches user discovery for the passed Facts. The searchCallback
@@ -389,7 +390,7 @@ func SearchUD(_ js.Value, args []js.Value) any {
 		sendReport, err := bindings.SearchUD(
 			e2eID, udContact, cb, factListJSON, singleRequestParamsJSON)
 		if err != nil {
-			reject(utils.JsTrace(err))
+			reject(exception.NewTrace(err))
 		} else {
 			resolve(utils.CopyBytesToJS(sendReport))
 		}
diff --git a/wasm/version.go b/wasm/version.go
index ee1a921cc666ef3a5e2491b5f43371ee098e2f3f..ca70bcbb150125aa427a271374632b4cef6118d8 100644
--- a/wasm/version.go
+++ b/wasm/version.go
@@ -14,8 +14,9 @@ import (
 	"syscall/js"
 
 	"gitlab.com/elixxir/client/v4/bindings"
+	"gitlab.com/elixxir/wasm-utils/exception"
+	"gitlab.com/elixxir/wasm-utils/utils"
 	"gitlab.com/elixxir/xxdk-wasm/storage"
-	"gitlab.com/elixxir/xxdk-wasm/utils"
 )
 
 // GetVersion returns the current xxDK WASM semantic version.
@@ -80,7 +81,7 @@ func GetWasmSemanticVersion(js.Value, []js.Value) any {
 
 	data, err := json.Marshal(vi)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 	}
 
 	return utils.CopyBytesToJS(data)
@@ -104,7 +105,7 @@ func GetXXDKSemanticVersion(js.Value, []js.Value) any {
 
 	data, err := json.Marshal(vi)
 	if err != nil {
-		utils.Throw(utils.TypeError, err)
+		exception.ThrowTrace(err)
 	}
 
 	return utils.CopyBytesToJS(data)
diff --git a/wasm_exec.js b/wasm_exec.js
index c6ae00c713c4bb089eb2d76d61d3e88aa0835839..5365a841cd2ff018149c25666e4b525a42bc1344 100644
--- a/wasm_exec.js
+++ b/wasm_exec.js
@@ -453,7 +453,7 @@
 					},
 
 					// func Throw(exception string, message string)
-					'gitlab.com/elixxir/xxdk-wasm/utils.throw': (sp) => {
+					'gitlab.com/elixxir/wasm-utils/exception.throw': (sp) => {
 						const exception = loadString(sp + 8)
 						const message = loadString(sp + 24)
 						throw globalThis[exception](message)
diff --git a/worker/manager.go b/worker/manager.go
index 3a5831db7c07a54927429b8d818dd66db7b9fc7a..2809a40922609923f300593a3120082afc46f5a5 100644
--- a/worker/manager.go
+++ b/worker/manager.go
@@ -18,7 +18,7 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/utils"
 )
 
 // initID is the ID for the first item in the callback list. If the list only
diff --git a/worker/thread.go b/worker/thread.go
index 203b00302a97c22f4e44501e2c721b52312c14ab..393ff7661db3f0c773932fdff932a15a3bfe92b9 100644
--- a/worker/thread.go
+++ b/worker/thread.go
@@ -17,7 +17,7 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 
-	"gitlab.com/elixxir/xxdk-wasm/utils"
+	"gitlab.com/elixxir/wasm-utils/utils"
 )
 
 // ThreadReceptionCallback is called with a message received from the main
@@ -244,8 +244,8 @@ func (tm *ThreadManager) addEventListeners() {
 	// Doc: https://developer.mozilla.org/en-US/docs/Web/API/Worker/error_event
 	errorEvent := js.FuncOf(func(_ js.Value, args []js.Value) any {
 		event := args[0]
-		jww.ERROR.Printf("[WW] [%s] Worker received error event: %s",
-			tm.name, utils.JsErrorToJson(event))
+		jww.ERROR.Printf("[WW] [%s] Worker received error event: %+v",
+			tm.name, js.Error{Value: event})
 		return nil
 	})
 
@@ -254,8 +254,8 @@ func (tm *ThreadManager) addEventListeners() {
 	// Doc: https://developer.mozilla.org/en-US/docs/Web/API/Worker/messageerror_event
 	messageerrorEvent := js.FuncOf(func(_ js.Value, args []js.Value) any {
 		event := args[0]
-		jww.ERROR.Printf("[WW] [%s] Worker received message error event: %s",
-			tm.name, utils.JsErrorToJson(event))
+		jww.ERROR.Printf("[WW] [%s] Worker received message error event: %+v",
+			tm.name, js.Error{Value: event})
 		return nil
 	})