Эх сурвалжийг харах

algo/builds: algorand mainnet builds

Josh Siegel 3 жил өмнө
parent
commit
5d71e619c1

+ 1 - 0
algorand/.gitignore

@@ -1,3 +1,4 @@
 __pycache__
 _sandbox
 genesis.json
+artifacts

+ 17 - 0
algorand/Dockerfile.build

@@ -0,0 +1,17 @@
+FROM docker.io/python:3.10@sha256:eeed7cac682f9274d183f8a7533ee1360a26acb3616aa712b2be7896f80d8c5f as algorand-contracts-build
+
+RUN python3 -m pip install virtualenv
+COPY Pipfile.lock Pipfile.lock
+COPY Pipfile Pipfile
+
+RUN python3 -m pip install pipenv
+RUN pipenv install
+RUN mkdir teal
+COPY *.py .
+
+RUN pipenv run python3 admin.py --mainnet --genTeal 
+
+FROM scratch AS algorand-contracts-export
+COPY --from=algorand-contracts-build /teal/* .
+
+

+ 11 - 0
algorand/Makefile

@@ -2,3 +2,14 @@
 
 test:
 	./runPythonUnitTests.sh
+
+.PHONY: artifacts
+artifacts:
+	rm -rf $@
+	mkdir -p $@
+	@echo "Building artifacts for algorand"
+	DOCKER_BUILDKIT=1 docker build -f Dockerfile.build -t algorand-builder -o type=local,dest=$@ .
+	../scripts/contract-upgrade-governance.sh  -m token_bridge -c algorand -a `cat artifacts/token_approve.teal.hash` -o artifacts
+	../scripts/contract-upgrade-governance.sh  -m core -c algorand -a `cat artifacts/core_approve.teal.hash` -o artifacts
+
+

+ 107 - 48
algorand/Pipfile.lock

@@ -1,11 +1,11 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "d57ff41afd46f1f82ef8cfa680858a40bda1d72482b073dba8666ac42275264f"
+            "sha256": "6571270ba10a2ef56432b1e20a02692ad00845c3faa0afa08ea0bcdc4e0ec185"
         },
         "pipfile-spec": 6,
         "requires": {
-            "python_version": "3.9"
+            "python_version": "3.10"
         },
         "sources": [
             {
@@ -148,25 +148,93 @@
         },
         "cytoolz": {
             "hashes": [
-                "sha256:ea23663153806edddce7e4153d1d407d62357c05120a4e8485bddf1bd5ab22b4"
+                "sha256:02583c9fd4668f9e343ad4fc0e0f9651b1a0c16fe92bd208d07fd07de90fdc99",
+                "sha256:02dc4565a8d27c9f3e87b715c0a300890e17c94ba1294af61c4ba97aa8482b22",
+                "sha256:09f5652caeac85e3735bd5aaed49ebf4eeb7c0f15cb9b7c4a5fb6f45308dc2fd",
+                "sha256:09fac69cebcb79a6ed75565fe2de9511be6e3d93f30dad115832cc1a3933b6ce",
+                "sha256:0c9fe89548b1dc7c8b3160758d192791b32bd42b1c244a20809a1053a9d74428",
+                "sha256:0f94b4a3500345de5853d1896b7e770ce4a6577a431f43ff7d8f05f9051aeb7d",
+                "sha256:12d3d11ceb0fce8be5463f1e363366888c4b71e68fb2f5d536e4790b933cfd7e",
+                "sha256:16748ea2b40c5978190d9acf9aa8fbacbfb440964c1035dc16cb14dbd557edb5",
+                "sha256:1744217505b835fcf55d82d67addd0d361791c4fd6a2f485f034b343ffc7edb3",
+                "sha256:1a79658fd264c5f82ea1b5cb45cf3899afabd9ec3e58c333bea042a2b4a94134",
+                "sha256:1c22255e7458feb6f43d99c9578396e91d5934757c552128f6afd3b093b41c00",
+                "sha256:1cf9ae77eed57924becd3ab65ae24487d7b1f9823d3e685d796e58f57424f82a",
+                "sha256:21986f4a970c03ca84806b3a08e89386ac4aeb54c9b79d6a7268e83225331a87",
+                "sha256:231d87ffb5fc468989e35336a2f8da1c9b8d97cfd9300cf2df32e953e4d20cae",
+                "sha256:25c037a7b4f49730ccc295a03cd2217ba67ff43ac0918299f5f368271433ff0f",
+                "sha256:274bc965cd93d6fa0bfe6f770cf6549bbe58d7b0a48dd6893d3f2c4b495d7f95",
+                "sha256:2bd1c692ab706acb46cfebe7105945b07f7274598097e32c8979d3b22ae62cc6",
+                "sha256:2d29cf7a44a8abaeb00537e3bad7abf823fce194fe707c366f81020d384e22f7",
+                "sha256:2ee9ca2cfc939607926096c7cc6f298cee125f8ca53a4f46745f8dfbb7fb7ab1",
+                "sha256:336551092eb1cfc2ad5878cc08ef290f744843f84c1dda06f9e4a84d2c440b73",
+                "sha256:337c9a3ce2929c6361bcc1b304ce81ed675078a34c203dbb7c3e154f7ed1cca8",
+                "sha256:38e3386f63ebaea46a4ee0bfefc9a38590c3b78ab86439766b5225443468a76b",
+                "sha256:3a5408a74df84e84aa1c86a2f9f2ffaed51a55f34bbad5b8fae547cb9167e977",
+                "sha256:3e8335998e21205574fc7d8d17844a9cc0dd4cbb25bb7716d90683a935d2c879",
+                "sha256:46b9f4af719b113c01a4144c52fc4b929f98a47017a5408e3910050f4641126b",
+                "sha256:4b8b1d9764d08782caa8ba0e91d76b95b973a82f4ce2a3f9c7e726bfeaddbdfa",
+                "sha256:59263f296e043d4210dd34f91e6f11c4b20e6195976da23170d5ad056030258a",
+                "sha256:5b7079b3197256ac6bf73f8b9484d514fac68a36d05513b9e5247354d6fc2885",
+                "sha256:68336dfbe00efebbb1d02b8aa00b570dceec5d03fbd818c620aa246a8f5e5409",
+                "sha256:69c04ae878d5bcde5462e7290f950bfce11fd139ec4b481687983326658e6dbe",
+                "sha256:6aade6ebb4507330b0540af58dc2804415945611e90c70bb97360973e487c48a",
+                "sha256:6f87472837c26b3bc91f9767c7adcfb935d0c097937c6744250672cd8c36019d",
+                "sha256:6fa49cfaa0eedad59d8357a482bd10e2cc2a12ad9f41aae53427e82d3eba068a",
+                "sha256:7244fb0d0b87499becc29051b82925e0daf3838e6c352e6b2d62e0f969b090af",
+                "sha256:798dff7a40adbb3dfa2d50499c2038779061ebc37eccedaf28fa296cb517b84e",
+                "sha256:79b46cda959f026bd9fc33b4046294b32bd5e7664a4cf607179f80ac93844e7f",
+                "sha256:7fe93ffde090e2867f8ce4369d0c1abf5651817a74a3d0a4da2b1ffd412603ff",
+                "sha256:8060be3b1fa24a4e3b165ce3c0ee6048f5e181289af57dbd9e3c4d4b8545dd78",
+                "sha256:8237612fed78d4580e94141a74ac0977f5a9614dd7fa8f3d2fcb30e6d04e73aa",
+                "sha256:886b3bf8fa99510836107097a5e5a2bd81631d3795dedc5684e25bef6538ac39",
+                "sha256:8c0101bb2b2bcc0de2e2eb288a132c261e5fa883b1423799b47d4f0cfd879cd6",
+                "sha256:8f40897f6f341e03a945759fcdb2208dc7c64dc312386d3088c47b78fca2a3b2",
+                "sha256:94b067c88de0eaca174211c8422b3f72cbfb63b101a0eeb528c4f21282ca0afe",
+                "sha256:9ac7758c5c5a66664285831261a9af8e0af504026e0987cd01535045945df6e1",
+                "sha256:9dd7dbdfc24ed309af96be170c9030f43713950afab2b4bed1d372a91b37cbb0",
+                "sha256:9e32292721f16516a574891a1af6760cba37a0f426a2b2cea6f9d560131a76ea",
+                "sha256:9ecdd6e2be8d59b76c2bd3e2d832e7b3d5b2535c418b13cfa85e3b17de985199",
+                "sha256:a15157f4280f6e5d7c2d0892847a6c4dffbd2c5cefccaf1ac1f1c6c3d2cf9936",
+                "sha256:a2cca43caea857e761cc458ffb4f7af397a13824c5e71341ca08035ff5ff0b27",
+                "sha256:a4acf6cb20f01a5eb5b6d459e08fb92aacfb4de8bc97e25437c1a3e71860b452",
+                "sha256:a8e69c9f3a32e0f9331cf6707a0f159c6dec0ff2a9f41507f6b2d06cd423f0d0",
+                "sha256:a8feb4d056c22983723278160aff8a28c507b0e942768f4e856539a60e7bb874",
+                "sha256:ae403cac13c2b9a2a92e56468ca1f822899b64d75d5be8ca802f1c14870d9133",
+                "sha256:ae7f417bb2b4e3906e525b3dbe944791dfa9248faea719c7a9c200aa1a019a4e",
+                "sha256:b05dc257996c0accf6f877b1f212f74dc134b39c46baac09e1894d9d9c970b6a",
+                "sha256:b716f66b5ee72dbf9a001316ffe72afe0bb8f6ce84e341aec64291c0ff16b9f4",
+                "sha256:bb0fc2ed8efa89f31ffa99246b1d434ff3db2b7b7e35147486172da849c8024a",
+                "sha256:c105b05f85e03fbcd60244375968e62e44fe798c15a3531c922d531018d22412",
+                "sha256:c4ff74cb0e1a50de7f59e54a156dfd734b6593008f6f804d0726a73b89d170cd",
+                "sha256:c818a382b828e960fbbedbc85663414edbbba816c2bf8c1bb5651305d79bdb97",
+                "sha256:c9f8c9b3cfa20b4ce6a89b7e2e7ffda76bdd81e95b7d20bbb2c47c2b31e72622",
+                "sha256:cb072fa81caab93a5892c4b69dfe0d48f52026a7fe83ba2567020a7995a456e7",
+                "sha256:d035805dcdefcdfe64d97d6e1e7603798588d5e1ae08e61a5dae3258c3cb407a",
+                "sha256:d212296e996a70db8d9e1c0622bc8aefa732eb0416b5441624d0fd5b853ea391",
+                "sha256:d511dd49eb1263ccb4e5f84ae1478dc2824d66b813cdf700e1ba593faa256ade",
+                "sha256:d61bc1713662e7d9aa3e298dad790dfd027c5c0f1342c36be8401aebe3d3d453",
+                "sha256:db619f17705067f1f112d3e84a0904b2f04117e50cefc4016f435ff0dc59bc4e",
+                "sha256:dc8df9adfca0da9956589f53764d459389ce86d824663c7217422232f1dfbc9d",
+                "sha256:dd840adfe027d379e7aede973bc0e193e6eef9b33d46d1d42826e26db9b37d7e",
+                "sha256:deb8550f487de756f1c24c56fa2c8451a53c0346868c13899c6b3a39b1f3d2c3",
+                "sha256:e17516a102731bcf86446ce148127a8cd2887cf27ac388990cd63881115b4fdc",
+                "sha256:ed8771e36430fb0e4398030569bdab1419e4e74f7bcd51ea57239aa95441983a",
+                "sha256:edf460dc6bed081f274cd3d8ae162dd7e382014161d65edcdec832035d93901b",
+                "sha256:ee1fe1a3d0c8c456c3fbf62f28d178f870d14302fcd1edbc240b717ae3ab08de",
+                "sha256:ee92dadb312e657b9b666a0385fafc6dad073d8a0fbef5cea09e21011554206a",
+                "sha256:ef4a496a3175aec595ae24ad03e0bb2fe76401f8f79e7ef3d344533ba990ec0e",
+                "sha256:f1f5c1ef04240b323b9e6b87d4b1d7f14b735e284a33b18a509537a10f62715c",
+                "sha256:f24e70d29223cde8ce3f5aefa7fd06bda12ae4386dcfbc726773e95b099cde0d",
+                "sha256:f26079bc2d0b7aa1a185516ac9f7cda0d7932da6c60589bfed4079e3a5369e83",
+                "sha256:f5784adcdb285e70b61efc1a369cd61c6b7f1e0b5d521651f93cde09549681f5",
+                "sha256:f71b49a41826a8e7fd464d6991134a6d022a666be4e76d517850abbea561c909",
+                "sha256:f909760f89a54d860cf960b4cd828f9f6301fb104cd0de5b15b16822c9c4828b",
+                "sha256:f959c1319b7e6ed3367b0f5a54a7b9c59063bd053c74278b27999db013e568df",
+                "sha256:fa5ded9f811c36668239adb4806fca1244b06add4d64af31119c279aab1ef8a6"
             ],
             "markers": "implementation_name == 'cpython'",
-            "version": "==0.11.2"
-        },
-        "dataclasses": {
-            "hashes": [
-                "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf",
-                "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"
-            ],
-            "markers": "python_version < '3.7'",
-            "version": "==0.8"
-        },
-        "decorator": {
-            "hashes": [
-                "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760",
-                "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"
-            ],
-            "version": "==4.4.2"
+            "version": "==0.12.0"
         },
         "eth-abi": {
             "hashes": [
@@ -178,11 +246,11 @@
         },
         "eth-hash": {
             "hashes": [
-                "sha256:3f40cecd5ead88184aa9550afc19d057f103728108c5102f592f8415949b5a76",
-                "sha256:de7385148a8e0237ba1240cddbc06d53f56731140f8593bdb8429306f6b42271"
+                "sha256:3c884e4f788b38cc92cff05c4e43bc6b82686066f04ecfae0e11cdcbe5a283bd",
+                "sha256:8cde211519ff1a98b46e9057cb909f12ab62e263eb30a0a94e2f7e1f46ac67a0"
             ],
             "markers": "python_version >= '3.5' and python_version < '4'",
-            "version": "==0.3.2"
+            "version": "==0.3.3"
         },
         "eth-typing": {
             "hashes": [
@@ -216,14 +284,6 @@
             "index": "pypi",
             "version": "==1.2.0"
         },
-        "importlib-metadata": {
-            "hashes": [
-                "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e",
-                "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"
-            ],
-            "markers": "python_version < '3.8'",
-            "version": "==4.8.3"
-        },
         "iniconfig": {
             "hashes": [
                 "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
@@ -274,11 +334,11 @@
         },
         "networkx": {
             "hashes": [
-                "sha256:0635858ed7e989f4c574c2328380b452df892ae85084144c73d8cd819f0c4e06",
-                "sha256:109cd585cac41297f71103c3c42ac6ef7379f29788eb54cb751be5a663bb235a"
+                "sha256:2a30822761f34d56b9a370d96a4bf4827a535f5591a4078a453425caeba0c5bb",
+                "sha256:bd2b7730300860cbd2dafe8e5af89ff5c9a65c3975b352799d87a6238b4301a6"
             ],
-            "markers": "python_version >= '3.6'",
-            "version": "==2.5.1"
+            "markers": "python_version >= '3.8'",
+            "version": "==2.8.6"
         },
         "packaging": {
             "hashes": [
@@ -429,11 +489,11 @@
         },
         "pyteal": {
             "hashes": [
-                "sha256:6c140db6ac365f438dc979c7de4153686ef97b762b9c4efe23bba0db4ff699e5",
-                "sha256:a72d1f0859f2248459bbcdbdfcd8cf09023ea003b121f0dbaf58289b8167d20c"
+                "sha256:29198b1e76121380430d9feaac4135c27b03b38e410b1c03f2c055feb9e533d6",
+                "sha256:937440d9562a425d53e1d4a74c357443435d1e74a407d5f4f87143767b4d4588"
             ],
             "index": "pypi",
-            "version": "==v0.10.0"
+            "version": "==v0.11.1"
         },
         "pytest": {
             "hashes": [
@@ -469,6 +529,7 @@
         },
         "pyyaml": {
             "hashes": [
+                "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf",
                 "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
                 "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
                 "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
@@ -480,26 +541,32 @@
                 "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
                 "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
                 "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
+                "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782",
                 "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
                 "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
                 "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
                 "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
                 "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
+                "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1",
                 "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
                 "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
                 "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
                 "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
                 "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
                 "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
+                "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d",
                 "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
                 "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
+                "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7",
                 "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
                 "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
                 "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
+                "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358",
                 "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
                 "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
                 "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
                 "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
+                "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f",
                 "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
                 "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
             ],
@@ -524,11 +591,11 @@
         },
         "toolz": {
             "hashes": [
-                "sha256:6b312d5e15138552f1bda8a4e66c30e236c831b612b2bf0005f8a1df10a4bc33",
-                "sha256:a5700ce83414c64514d82d60bcda8aabfde092d1c1a8663f9200c07fdcc6da8f"
+                "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f",
+                "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"
             ],
             "markers": "python_version >= '3.5'",
-            "version": "==0.11.2"
+            "version": "==0.12.0"
         },
         "typing-extensions": {
             "hashes": [
@@ -545,14 +612,6 @@
             ],
             "index": "pypi",
             "version": "==1.2.0"
-        },
-        "zipp": {
-            "hashes": [
-                "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832",
-                "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"
-            ],
-            "markers": "python_version >= '3.6'",
-            "version": "==3.6.0"
         }
     },
     "develop": {}

+ 81 - 26
algorand/admin.py

@@ -283,12 +283,8 @@ class PortalCore:
     
     # helper function to read app global state
     def read_global_state(self, client, addr, app_id):
-        results = client.account_info(addr)
-        apps_created = results['created-apps']
-        for app in apps_created:
-            if app['id'] == app_id and 'global-state' in app['params']:
-                return self.format_state(app['params']['global-state'])
-        return {}
+        results = self.client.application_info(app_id)
+        return self.format_state(results['params']['global-state'])
 
     def read_state(self, client, addr, app_id):
         results = client.account_info(addr)
@@ -355,8 +351,13 @@ class PortalCore:
         return -1
 
     def genUpgradePayload(self):
-        approval, clear = getCoreContracts(False, self.args.core_approve, self.args.core_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = self.devnet or self.args.testnet)
+        approval1, clear1 = getCoreContracts(False, self.args.core_approve, self.args.core_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = self.devnet or self.args.testnet)
+
+        approval2, clear2 = get_token_bridge(False, self.args.token_approve, self.args.token_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = self.devnet or self.args.testnet)
+
+        return self.genUpgradePayloadBody(approval1, approval2)
 
+    def genUpgradePayloadBody(self, approval1, approval2):
         b  = self.zeroPadBytes[0:(28*2)]
         b += self.encoder("uint8", ord("C"))
         b += self.encoder("uint8", ord("o"))
@@ -365,14 +366,11 @@ class PortalCore:
         b += self.encoder("uint8", 1)
         b += self.encoder("uint16", 8)
 
-        b += decode_address(approval["hash"]).hex()
-        print("core hash: " + decode_address(approval["hash"]).hex())
+        b += decode_address(approval1["hash"]).hex()
+        print("core hash: " + decode_address(approval1["hash"]).hex())
 
         ret = [b]
 
-        approval, clear = get_token_bridge(False, self.args.token_approve, self.args.token_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = self.devnet or self.args.testnet)
-
-
         b  = self.zeroPadBytes[0:((32 -11)*2)]
         b += self.encoder("uint8", ord("T"))
         b += self.encoder("uint8", ord("o"))
@@ -388,8 +386,8 @@ class PortalCore:
 
         b += self.encoder("uint8", 2)  # action
         b += self.encoder("uint16", 8) # target chain
-        b += decode_address(approval["hash"]).hex()
-        print("token hash: " + decode_address(approval["hash"]).hex())
+        b += decode_address(approval2["hash"]).hex()
+        print("token hash: " + decode_address(approval2["hash"]).hex())
 
         ret.append(b)
         return ret
@@ -1282,9 +1280,18 @@ class PortalCore:
 
     def updateCore(self) -> None:
         print("Updating the core contracts")
-        approval, clear = getCoreContracts(False, self.args.core_approve, self.args.core_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = self.devnet or self.args.testnet)
-
-        print("core " + decode_address(approval["hash"]).hex())
+        if self.args.approve == "" and self.args.clear == "":
+            approval, clear = getCoreContracts(False, self.args.core_approve, self.args.core_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = self.devnet or self.args.testnet)
+            print("core approval " + decode_address(approval["hash"]).hex())
+            print("core clear " + decode_address(clear["hash"]).hex())
+        else:
+            pprint.pprint([self.args.approve, self.args.clear])
+            with open(self.args.approve, encoding = 'utf-8') as f:
+                approval = {"result": f.readlines()[0]}
+                pprint.pprint(approval)
+            with open(self.args.clear, encoding = 'utf-8') as f:
+                clear = {"result": f.readlines()[0]}
+                pprint.pprint(clear)
 
         txn = transaction.ApplicationUpdateTxn(
             index=self.coreid,
@@ -1299,6 +1306,7 @@ class PortalCore:
         print("sending transaction")
         self.client.send_transaction(signedTxn)
         resp = self.waitForTransaction(self.client, signedTxn.get_txid())
+        pprint.pprint(resp)
         for x in resp.__dict__["logs"]:
             print(x.hex())
         print("complete")
@@ -1329,10 +1337,30 @@ class PortalCore:
 
     def genTeal(self) -> None:
         print((True, self.args.core_approve, self.args.core_clear, self.client, self.seed_amt, self.tsig, self.devnet or self.args.testnet))
-        approval, clear = getCoreContracts(True, self.args.core_approve, self.args.core_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = self.devnet or self.args.testnet)
+        devmode = (self.devnet or self.args.testnet) and not self.args.prodTeal
+        approval1, clear1 = getCoreContracts(True, self.args.core_approve, self.args.core_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = devmode)
         print("Generating the teal for the core contracts")
-        approval, clear = get_token_bridge(True, self.args.token_approve, self.args.token_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = self.devnet or self.args.testnet)
-        print("Generating the teal for the token contracts: " + str(len(b64decode(approval["result"]))))
+        approval2, clear2 = get_token_bridge(True, self.args.token_approve, self.args.token_clear, self.client, seed_amt=self.seed_amt, tmpl_sig=self.tsig, devMode = devmode)
+        print("Generating the teal for the token contracts: " + str(len(b64decode(approval2["result"]))))
+
+        if self.devnet:
+            v = self.genUpgradePayloadBody(approval1, approval2)
+            if self.gt == None:
+                self.gt = GenTest(False)
+    
+            emitter = bytes.fromhex(self.zeroPadBytes[0:(31*2)] + "04")
+    
+            guardianSet = 0
+    
+            nonce = int(random.random() * 20000)
+            coreVAA = self.gt.createSignedVAA(guardianSet, self.gt.guardianPrivKeys, int(time.time()), nonce, 1, emitter, int(random.random() * 20000), 32, 8, v[0])
+            tokenVAA = self.gt.createSignedVAA(guardianSet, self.gt.guardianPrivKeys, int(time.time()), nonce, 1, emitter, int(random.random() * 20000), 32, 8, v[1])
+    
+            with open("teal/core_devnet.vaa", "w") as fout:
+                fout.write(coreVAA)
+    
+            with open("teal/token_devnet.vaa", "w") as fout:
+                fout.write(tokenVAA)
 
     def testnet(self):
         self.ALGOD_ADDRESS = self.args.algod_address = "https://testnet-api.algonode.cloud"
@@ -1343,8 +1371,12 @@ class PortalCore:
     def mainnet(self):
         self.ALGOD_ADDRESS = self.args.algod_address = "https://mainnet-api.algonode.cloud"
         self.INDEXER_ADDRESS = "https://mainnet-idx.algonode.cloud"
-        self.coreid = self.args.coreid
-        self.tokenid = self.args.tokenid
+        self.coreid = 842125965
+        self.tokenid = 842126029
+        if self.args.coreid != 4:
+            self.coreid = self.args.coreid
+        if self.args.coreid != 6:
+            self.tokenid = self.args.tokenid
 
     def setup_args(self) -> None:
         parser = argparse.ArgumentParser(description='algorand setup')
@@ -1384,6 +1416,7 @@ class PortalCore:
         parser.add_argument('--upgradeVAA', action='store_true', help='generate a upgrade vaa for devnet')
         parser.add_argument('--print', action='store_true', help='print')
         parser.add_argument('--genParts', action='store_true', help='Get tssig parts')
+        parser.add_argument('--prodTeal', action='store_true', help='use Production Deal')
         parser.add_argument('--genTeal', action='store_true', help='Generate all the teal from the pyteal')
         parser.add_argument('--fund', action='store_true', help='Generate some accounts and fund them')
         parser.add_argument('--testnet', action='store_true', help='Connect to testnet')
@@ -1392,6 +1425,8 @@ class PortalCore:
         parser.add_argument('--rpc', type=str, help='RPC address', default="")
         parser.add_argument('--guardianKeys', type=str, help='GuardianKeys', default="")
         parser.add_argument('--guardianPrivKeys', type=str, help='guardianPrivKeys', default="")
+        parser.add_argument('--approve', type=str, help='compiled approve contract', default="")
+        parser.add_argument('--clear', type=str, help='compiled clear contract', default="")
 
         args = parser.parse_args()
         self.init(args)
@@ -1413,6 +1448,7 @@ class PortalCore:
             self.ALGOD_ADDRESS = self.args.rpc
             
         self.client = self.getAlgodClient()
+
         if self.devnet or self.args.testnet:
             self.vaa_verify = self.client.compile(get_vaa_verify())
         else:
@@ -1485,12 +1521,31 @@ class PortalCore:
             ret = self.devnetUpgradeVAA()
             pprint.pprint(ret)
             if (args.submit) :
-                print("submitting vaa to upgrade core")
+                print("submitting vaa to upgrade core: " + str(self.coreid))
+                state = self.read_global_state(self.client, self.foundation.addr, self.coreid)
+                pprint.pprint( { 
+                    "validUpdateApproveHash": b64decode(state["validUpdateApproveHash"]).hex(),
+                    "validUpdateClearHash": b64decode(state["validUpdateClearHash"]).hex()
+                })
                 self.submitVAA(bytes.fromhex(ret[0]), self.client, self.foundation, self.coreid)
-                pprint.pprint(self.read_global_state(self.client, self.foundation.addr, self.coreid))
-                print("submitting vaa to upgrade token")
+                state = self.read_global_state(self.client, self.foundation.addr, self.coreid)
+                pprint.pprint( { 
+                    "validUpdateApproveHash": b64decode(state["validUpdateApproveHash"]).hex(),
+                    "validUpdateClearHash": b64decode(state["validUpdateClearHash"]).hex()
+                })
+
+                print("submitting vaa to upgrade token: " + str(self.tokenid))
+                state = self.read_global_state(self.client, self.foundation.addr, self.tokenid)
+                pprint.pprint( { 
+                    "validUpdateApproveHash": b64decode(state["validUpdateApproveHash"]).hex(),
+                    "validUpdateClearHash": b64decode(state["validUpdateClearHash"]).hex()
+                })
                 self.submitVAA(bytes.fromhex(ret[1]), self.client, self.foundation, self.tokenid)
-                pprint.pprint(self.read_global_state(self.client, self.foundation.addr, self.tokenid))
+                state = self.read_global_state(self.client, self.foundation.addr, self.tokenid)
+                pprint.pprint( { 
+                    "validUpdateApproveHash": b64decode(state["validUpdateApproveHash"]).hex(),
+                    "validUpdateClearHash": b64decode(state["validUpdateClearHash"]).hex()
+                })
 
         if args.boot:
             self.boot()

+ 0 - 8
algorand/teal/README

@@ -1,8 +0,0 @@
-
-While these are generated files, due to the non-deterministic behavior
-of the pyteal compiler based on what has been done before, we cannot
-reliably recreate the exact same teal file from the exact same pyteal
-source.
-
-As a result, we need to check the generated files in so that we can
-verify the hash of the compiled code while generating upgrade vaa's

+ 35 - 8
algorand/teal/core_approve.teal

@@ -1,6 +1,6 @@
 #pragma version 6
 intcblock 1 0 127 2 1000 86400 128 255
-bytecblock 0x 0x0008 0x677561726469616e 0x63757272656e74477561726469616e536574496e646578 0x6e6f70 0x76657269667953696773 0x4d657373616765466565 0x76616c6964557064617465417070726f766548617368 0x766572696679564141 0x767068617368 0x50726f6772616d 0x7075626c6973684d657373616765 0x0001 0x0000000000000000000000000000000000000000000000000000000000000004 0x00000000000000000000000000000000000000000000000000000000436f7265 0x0000 0x626f6f746564 0x76616c6964557064617465436c65617248617368 0x6d657461
+bytecblock 0x 0x0008 0x677561726469616e 0x63757272656e74477561726469616e536574496e646578 0x6e6f70 0x76657269667953696773 0x4d657373616765466565 0x76616c6964557064617465417070726f766548617368 0x767068617368 0x766572696679564141 0x50726f6772616d 0x7075626c6973684d657373616765 0x0001 0x0000000000000000000000000000000000000000000000000000000000000004 0x00000000000000000000000000000000000000000000000000000000436f7265 0x0000 0x626f6f746564 0x76616c6964557064617465436c65617248617368 0x6d657461
 txn ApplicationID
 intc_1 // 0
 ==
@@ -40,7 +40,7 @@ bytec 5 // "verifySigs"
 ==
 bnz main_l51
 txna ApplicationArgs 0
-bytec 8 // "verifyVAA"
+bytec 9 // "verifyVAA"
 ==
 bnz main_l29
 txna ApplicationArgs 0
@@ -67,7 +67,7 @@ txn GroupIndex
 intc_0 // 1
 -
 gtxnsa ApplicationArgs 0
-bytec 8 // "verifyVAA"
+bytec 9 // "verifyVAA"
 ==
 &&
 txn GroupIndex
@@ -87,6 +87,13 @@ global ZeroAddress
 txn GroupIndex
 intc_0 // 1
 -
+gtxns OnCompletion
+intc_1 // NoOp
+==
+&&
+txn GroupIndex
+intc_0 // 1
+-
 gtxnsa ApplicationArgs 1
 txna ApplicationArgs 1
 ==
@@ -555,7 +562,7 @@ bytec 4 // "nop"
 ==
 bnz main_l41
 load 11
-bytec 8 // "verifyVAA"
+bytec 9 // "verifyVAA"
 ==
 bnz main_l41
 intc_0 // 1
@@ -576,6 +583,11 @@ main_l42:
 load 10
 gtxnsa ApplicationArgs 1
 store 18
+load 18
+len
+intc_1 // 0
+>
+assert
 txna ApplicationArgs 1
 load 15
 load 18
@@ -602,7 +614,7 @@ load 18
 ==
 load 10
 gtxns Sender
-bytec 9 // "vphash"
+bytec 8 // "vphash"
 app_global_get
 ==
 &&
@@ -676,10 +688,13 @@ load 18
 assert
 b main_l30
 main_l51:
-intc_0 // 1
+txn Sender
+bytec 8 // "vphash"
+app_global_get
+==
 return
 main_l52:
-bytec 9 // "vphash"
+bytec 8 // "vphash"
 txna ApplicationArgs 2
 app_global_put
 txn Sender
@@ -1052,7 +1067,7 @@ main_l75:
 bytec 6 // "MessageFee"
 intc_1 // 0
 app_global_put
-bytec 9 // "vphash"
+bytec 8 // "vphash"
 bytec_0 // ""
 app_global_put
 bytec_3 // "currentGuardianSetIndex"
@@ -1420,6 +1435,10 @@ gtxn 0 Amount
 pushint 1002000 // 1002000
 ==
 &&
+gtxn 0 Receiver
+gtxn 1 Sender
+==
+&&
 gtxn 1 TypeEnum
 pushint 6 // appl
 ==
@@ -1432,6 +1451,14 @@ gtxn 1 ApplicationID
 global CurrentApplicationID
 ==
 &&
+gtxn 1 RekeyTo
+global CurrentApplicationAddress
+==
+&&
+gtxn 1 NumAppArgs
+intc_1 // 0
+==
+&&
 assert
 intc_1 // 0
 callsub zero_1

+ 0 - 65
algorand/teal/sig.tmpl.teal

@@ -1,65 +0,0 @@
-#pragma version 6
-intcblock 1
-pushint TMPL_ADDR_IDX // TMPL_ADDR_IDX
-pop
-pushbytes TMPL_EMITTER_ID // TMPL_EMITTER_ID
-pop
-callsub init_0
-return
-
-// init
-init_0:
-global GroupSize
-pushint 3 // 3
-==
-assert
-gtxn 0 TypeEnum
-intc_0 // pay
-==
-assert
-gtxn 0 Amount
-pushint TMPL_SEED_AMT // TMPL_SEED_AMT
-==
-assert
-gtxn 0 RekeyTo
-global ZeroAddress
-==
-assert
-gtxn 0 CloseRemainderTo
-global ZeroAddress
-==
-assert
-gtxn 1 TypeEnum
-pushint 6 // appl
-==
-assert
-gtxn 1 OnCompletion
-intc_0 // OptIn
-==
-assert
-gtxn 1 ApplicationID
-pushint TMPL_APP_ID // TMPL_APP_ID
-==
-assert
-gtxn 1 RekeyTo
-global ZeroAddress
-==
-assert
-gtxn 2 TypeEnum
-intc_0 // pay
-==
-assert
-gtxn 2 Amount
-pushint 0 // 0
-==
-assert
-gtxn 2 RekeyTo
-pushbytes TMPL_APP_ADDRESS // TMPL_APP_ADDRESS
-==
-assert
-gtxn 2 CloseRemainderTo
-global ZeroAddress
-==
-assert
-intc_0 // 1
-return

+ 91 - 2
algorand/teal/token_approve.teal

@@ -95,6 +95,11 @@ txn Sender
 ==
 &&
 load 68
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
+load 68
 gtxnsa ApplicationArgs 1
 txna ApplicationArgs 1
 ==
@@ -148,6 +153,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 68
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 txn RekeyTo
 global ZeroAddress
@@ -160,6 +170,10 @@ txn AssetCloseTo
 global ZeroAddress
 ==
 &&
+txn OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 txna ApplicationArgs 1
 load 62
@@ -274,6 +288,10 @@ txn AssetCloseTo
 global ZeroAddress
 ==
 &&
+txn OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 itxn_begin
 txna Accounts 1
@@ -348,6 +366,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 load 22
 gtxns AssetAmount
@@ -589,6 +612,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 load 22
 gtxns Amount
@@ -628,6 +656,11 @@ txn Sender
 ==
 &&
 load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
+load 22
 gtxnsa ApplicationArgs 1
 txna ApplicationArgs 1
 ==
@@ -662,6 +695,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 txn RekeyTo
 global ZeroAddress
@@ -674,6 +712,10 @@ txn AssetCloseTo
 global ZeroAddress
 ==
 &&
+txn OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 txna ApplicationArgs 1
 extract 5 1
@@ -1137,6 +1179,11 @@ txn Sender
 ==
 &&
 load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
+load 22
 gtxnsa ApplicationArgs 1
 txna ApplicationArgs 1
 ==
@@ -1171,6 +1218,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 txn GroupIndex
 pushint 3 // 3
@@ -1210,6 +1262,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 txn GroupIndex
 intc_2 // 2
@@ -1249,6 +1306,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 txn GroupIndex
 intc_1 // 1
@@ -1294,6 +1356,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 txna ApplicationArgs 1
 extract 5 1
@@ -1386,8 +1453,6 @@ bnz main_l76
 main_l71:
 load 30
 callsub trimbytes_13
-pushbytes 0x2028576f726d686f6c6529 // " (Wormhole)"
-concat
 store 30
 load 28
 pushint 8 // 8
@@ -1860,6 +1925,11 @@ gtxns AssetCloseTo
 global ZeroAddress
 ==
 &&
+load 22
+gtxns OnCompletion
+intc_0 // NoOp
+==
+&&
 assert
 checkFeePmt_10_l2:
 retsub
@@ -2188,6 +2258,13 @@ gtxns Amount
 pushint 1002000 // 1002000
 ==
 &&
+txn GroupIndex
+intc_1 // 1
+-
+gtxns Receiver
+txn Sender
+==
+&&
 txn TypeEnum
 pushint 6 // appl
 ==
@@ -2196,6 +2273,18 @@ txn OnCompletion
 intc_1 // OptIn
 ==
 &&
+txn ApplicationID
+global CurrentApplicationID
+==
+&&
+txn RekeyTo
+global CurrentApplicationAddress
+==
+&&
+txn NumAppArgs
+intc_0 // 0
+==
+&&
 assert
 intc_0 // 0
 callsub zero_1

+ 12 - 10
algorand/token_bridge.py

@@ -25,6 +25,7 @@ from globals import *
 from inlineasm import *
 
 from algosdk.v2client.algod import AlgodClient
+from algosdk.encoding import decode_address
 
 from TmplSig import TmplSig
 from local_blob import LocalBlob
@@ -58,6 +59,12 @@ def fullyCompileContract(genTeal, client: AlgodClient, contract: Expr, name, dev
             teal = f.read()
 
     response = client.compile(teal)
+
+    with open(name + ".bin", "w") as fout:
+        fout.write(response["result"])
+    with open(name + ".hash", "w") as fout:
+        fout.write(decode_address(response["hash"]).hex())
+
     return response
 
 def clear_token_bridge():
@@ -961,16 +968,11 @@ def approve_token_bridge(seed_amt: int, tmpl_sig: TmplSig, devMode: bool):
     ])
 
     def getOnUpdate():
-        if devMode:
-            return Seq( [
-                Return(Txn.sender() == Global.creator_address()),
-            ])
-        else:
-            return Seq( [
-                MagicAssert(Sha512_256(Concat(Bytes("Program"), Txn.approval_program())) == App.globalGet(Bytes("validUpdateApproveHash"))),
-                MagicAssert(Sha512_256(Concat(Bytes("Program"), Txn.clear_state_program())) == App.globalGet(Bytes("validUpdateClearHash"))),
-                Return(Int(1))
-            ] )
+        return Seq( [
+            MagicAssert(Sha512_256(Concat(Bytes("Program"), Txn.approval_program())) == App.globalGet(Bytes("validUpdateApproveHash"))),
+            MagicAssert(Sha512_256(Concat(Bytes("Program"), Txn.clear_state_program())) == App.globalGet(Bytes("validUpdateClearHash"))),
+            Return(Int(1))
+        ] )
 
     on_update = getOnUpdate()
 

+ 11 - 10
algorand/wormhole_core.py

@@ -50,6 +50,12 @@ def fullyCompileContract(genTeal, client: AlgodClient, contract: Expr, name, dev
             teal = f.read()
 
     response = client.compile(teal)
+
+    with open(name + ".bin", "w") as fout:
+        fout.write(response["result"])
+    with open(name + ".hash", "w") as fout:
+        fout.write(decode_address(response["hash"]).hex())
+
     return response
 
 def getCoreContracts(   genTeal, approve_name, clear_name,
@@ -563,16 +569,11 @@ def getCoreContracts(   genTeal, approve_name, clear_name,
         clearSet = ScratchVar()
 
         def getOnUpdate():
-            if devMode:
-                return Seq( [
-                    Return(Txn.sender() == Global.creator_address()),
-                ])
-            else:
-                return Seq( [
-                    MagicAssert(Sha512_256(Concat(Bytes("Program"), Txn.approval_program())) == App.globalGet(Bytes("validUpdateApproveHash"))),
-                    MagicAssert(Sha512_256(Concat(Bytes("Program"), Txn.clear_state_program())) == App.globalGet(Bytes("validUpdateClearHash"))),
-                    Return(Int(1))
-                ] )
+            return Seq( [
+                MagicAssert(Sha512_256(Concat(Bytes("Program"), Txn.approval_program())) == App.globalGet(Bytes("validUpdateApproveHash"))),
+                MagicAssert(Sha512_256(Concat(Bytes("Program"), Txn.clear_state_program())) == App.globalGet(Bytes("validUpdateClearHash"))),
+                Return(Int(1))
+            ] )
 
         on_update = getOnUpdate()
         

+ 1 - 1
clients/js/algorand.ts

@@ -54,7 +54,7 @@ export async function execute_algorand(
         // NOTE: this code can safely be removed once the algorand NFT bridge is
         // released, but it's fine for it to stay, as the condition will just be
         // skipped once 'contracts.nft_bridge' is defined
-        throw new Error("NFT bridge not supported yet for terra");
+        throw new Error("NFT bridge not supported yet for algorand");
       }
       target_contract = contracts.nft_bridge;
       switch (payload.type) {

+ 30 - 0
scripts/contract-upgrade-governance.sh

@@ -141,6 +141,10 @@ case "$chain_name" in
     explorer="https://aurorascan.dev/address/"
     evm=true
     ;;
+  algorand)
+    chain=8
+    explorer="https://algoexplorer.io/address/"
+    ;;
   fantom)
     chain=10
     explorer="https://ftmscan.com/address/"
@@ -261,6 +265,20 @@ function near_artifact() {
   esac
 }
 
+function algorand_artifact() {
+  case "$module" in
+  bridge|core)
+    echo "artifacts/core_approve.teal.hash"
+    ;;
+  token_bridge)
+    echo "artifacts/token_approve.teal.hash"
+    ;;
+  *) echo "unknown module $module" >&2
+     usage
+     ;;
+  esac
+}
+
 function terra_artifact() {
   case "$module" in
   bridge|core)
@@ -401,6 +419,18 @@ elif [ "$chain_name" = "near" ]; then
 	wormhole/near$ sha256sum $(near_artifact)
 	\`\`\`
 EOF
+elif [ "$chain_name" = "algorand" ]; then
+  cat <<-EOF >> "$instructions_file"
+	## Build
+	\`\`\`shell
+	wormhole/algorand $ make artifacts
+	\`\`\`
+
+	This command will compile all the contracts into the \`artifacts\` directory using Docker to ensure that the build artifacts are deterministic.
+
+	You can then review $(algorand_artifact) to confirm the supplied hash value
+
+EOF
 elif [ "$chain_name" = "terra" ]; then
   cat <<-EOF >> "$instructions_file"
 	## Build