{"id":601,"date":"2023-12-07T14:06:11","date_gmt":"2023-12-07T12:06:11","guid":{"rendered":"https:\/\/ackeeblockchain.com\/blog\/?p=601"},"modified":"2025-11-03T12:55:56","modified_gmt":"2025-11-03T10:55:56","slug":"on-the-wave-of-ci-cd-for-web3","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/on-the-wave-of-ci-cd-for-web3\/","title":{"rendered":"On the wave of CI\/CD for Web3"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">So you want to write and deploy a smart contract, huh?\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Go for it and do it as a professional, use the best practices common for the best software out there. There is no need to reinvent the wheel and change processes that work.\u00a0 Sometimes we just need to adjust the tooling &#8211; and that\u2019s what this article is about.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Let\u2019s set up this environment for a sample project from scratch.<\/span><\/p>\n<h2><b>How to set up a continuous integration and continuous deployment (CI\/CD) environment for crypto projects<br \/>\n<\/b><\/h2>\n<h4><b>Setting up the repository<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Starting with two repositories is considered to be a good practice. One is public for the main activity, and the second is private and also holds the codebase because some activity on the project should not be discussed publicly, for example, live vulnerabilities\/security patches that could affect users. This approach helps us to avoid hackers who could exploit a disclosed bug in pull requests before it is fixed for the released code.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">To avoid complicating this tutorial, we will stick only to a public repository (on GitHub).<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Let\u2019s start going step by step through repository settings and consider changing crucial parameters, such as branch protection rules or access controls for the team.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-603 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_1661176409.jpeg\" alt=\"\" width=\"535\" height=\"281\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1661176409.jpeg 1338w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1661176409-300x157.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1661176409-1024x537.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1661176409-768x403.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1661176409-370x194.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1661176409-760x399.jpeg 760w\" sizes=\"auto, (max-width: 535px) 100vw, 535px\" \/><\/p>\n<h4><b>Initialize the project<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Clone your empty repository and enter it. In the repository folder, initialize the template for your project with:<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">This command will prepare all needed folders, including the .gitignore file.<\/span><\/p>\n<h4><b>Write the code<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Now, we are ready to write the code. Let\u2019s start with the following one generated by <\/span><a href=\"https:\/\/wizard.openzeppelin.com\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">OpenZeppelin Solidity Wizard<\/span><\/a><span style=\"font-weight: 400;\"> with a few changes (bugs).<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/2d3df360dae2c91f30be504c2fe7526a.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">This code includes some packages, so we must add them with npm (don\u2019t forget to add node_modules to .gitignore).<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/1f1a1b4fb24f84ac6599c7e83211684b.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">When we have installed the packages, we can test the compilation.<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/190cd3ab3156d4a0a25343f2050ede9a.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">In the current state, we have a working project with the following structure.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-604 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_4188970706.jpeg\" alt=\"\" width=\"453\" height=\"376\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_4188970706.jpeg 1198w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_4188970706-300x249.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_4188970706-1024x850.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_4188970706-768x637.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_4188970706-370x307.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_4188970706-760x631.jpeg 760w\" sizes=\"auto, (max-width: 453px) 100vw, 453px\" \/><\/p>\n<h4><b>Write tests<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Firstly, we need to initialize pytypes against the source code:<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/8f418ef07b056e6cb1cb6eaf12b2d700.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">Then we will write some basic test:<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/21ecacff64902f9f2e5f59ced476d184.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">And we can run the tests with:<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/270600b7b01fc1ec88ec0fad84bfda7f.js\"><\/script><\/p>\n<h4><b>Write deployment scripts<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">We will be deploying our contract to Holesky testnet. Writing deployment scripts is very similar to writing tests.<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/0b1ac36e524a08ca3f51e792f5516016.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">Before deploying, we need to set the private key in .env file and retrieve it using dotenv library, and then we can test deployment.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-605 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_1748073175.jpeg\" alt=\"\" width=\"575\" height=\"253\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1748073175.jpeg 1306w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1748073175-300x132.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1748073175-1024x450.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1748073175-768x338.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1748073175-370x163.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_1748073175-760x334.jpeg 760w\" sizes=\"auto, (max-width: 575px) 100vw, 575px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Everything works as expected: tests, deployment, and compilation, so we can proceed to writing the pipeline to have these steps automated.<\/span><\/p>\n<h4><b>Write pipeline<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">We will start with creating a folder for our pipeline:<\/span><\/p>\n<p><span style=\"font-weight: 400;\"><script src=\"https:\/\/gist.github.com\/encryptedbae\/ff891dd9ebc20403b8ad50a5c5d9c369.js\"><\/script><br \/>\n<\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><span style=\"font-weight: 400;\">Then, in this folder, we will create the following file: pipeline.yml.<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/dbf90fe8d5b7303169b32caad9893687.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">We have two jobs. One is for pull requests to master testing and analyzing the new code that will be merged. The second job is for deployment, and it\u2019s triggered only on merge\/push to master. We are using <\/span><a href=\"https:\/\/github.com\/marketplace\/actions\/wake-setup\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Wake Setup action<\/span><\/a><span style=\"font-weight: 400;\"> to set up the environment for tests and deployment. Then, we are using specialized <\/span><a href=\"https:\/\/github.com\/marketplace\/actions\/wake-detect\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Wake Detect action<\/span><\/a><span style=\"font-weight: 400;\"> for code scanning for vulnerabilities. In the deployment part, we must pass a private key with dotenv via GitHub secrets. That secret has to be set in repository settings.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-606 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_484937606.jpeg\" alt=\"\" width=\"509\" height=\"86\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_484937606.jpeg 1204w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_484937606-300x51.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_484937606-1024x174.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_484937606-768x130.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_484937606-370x63.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_484937606-760x129.jpeg 760w\" sizes=\"auto, (max-width: 509px) 100vw, 509px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Once we set a secret, we are good to go.<\/span><\/p>\n<h4><b>Deploy<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Everything is set. We can check out to another branch and push our codebase. After push, nothing is triggered because we don\u2019t have a pipeline defined for this behavior. That\u2019s expected.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">After creating a pull request, we can see the pipeline is triggered (skipping deploy).<\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-607 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_3924795189.jpeg\" alt=\"\" width=\"392\" height=\"184\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3924795189.jpeg 1194w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3924795189-300x141.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3924795189-1024x480.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3924795189-768x360.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3924795189-370x174.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3924795189-760x356.jpeg 760w\" sizes=\"auto, (max-width: 392px) 100vw, 392px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Apparently, since we didn\u2019t run static analysis before, we can see the pipeline detected bugs and attached them to our pull request.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-608 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_3825052230.jpeg\" alt=\"\" width=\"498\" height=\"469\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3825052230.jpeg 1196w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3825052230-300x283.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3825052230-1024x966.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3825052230-768x724.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3825052230-370x349.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_3825052230-760x717.jpeg 760w\" sizes=\"auto, (max-width: 498px) 100vw, 498px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">So, with our repository policies, we may not be able to merge to master until it is fully resolved.<\/span><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-609 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_2392587519.jpeg\" alt=\"\" width=\"493\" height=\"114\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2392587519.jpeg 1200w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2392587519-300x70.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2392587519-1024x237.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2392587519-768x178.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2392587519-370x86.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2392587519-760x176.jpeg 760w\" sizes=\"auto, (max-width: 493px) 100vw, 493px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">We go back to the code to fix it. Remove unused import and replace tx.origin with msg.sender.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now we can see we are ready to deploy.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-610 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_101926557.jpeg\" alt=\"\" width=\"493\" height=\"173\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_101926557.jpeg 1200w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_101926557-300x106.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_101926557-1024x360.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_101926557-768x270.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_101926557-370x130.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_101926557-760x267.jpeg 760w\" sizes=\"auto, (max-width: 493px) 100vw, 493px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-611 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_2724405917.jpeg\" alt=\"\" width=\"494\" height=\"256\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2724405917.jpeg 1200w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2724405917-300x156.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2724405917-1024x531.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2724405917-768x398.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2724405917-370x192.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_2724405917-760x394.jpeg 760w\" sizes=\"auto, (max-width: 494px) 100vw, 494px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Let\u2019s merge it!<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-612 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/12\/tg_image_196534388.jpeg\" alt=\"\" width=\"495\" height=\"226\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_196534388.jpeg 1196w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_196534388-300x137.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_196534388-1024x467.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_196534388-768x351.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_196534388-370x169.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/tg_image_196534388-760x347.jpeg 760w\" sizes=\"auto, (max-width: 495px) 100vw, 495px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">We successfully deployed the contract via GitHub actions.<\/span><\/p>\n<h4><b>Final remarks<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">This tutorial explained how to use GitHub actions to enhance your CI\/CD processes.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">These actions will help you make your project more durable and efficient. The provided example is purely informational, and now it\u2019s on you to find the best match for your project.<\/span><\/p>\n<p>It goes without saying that you should\u00a0<strong>never include sensitive data such as API keys, passwords, or dev wallet addresses in public code<\/strong>. Place these into your .env file and if you need to share them, use a password manager such as Passwd.<\/p>\n<p>We work with sensitive infrastructure all the time, from auditing smart contracts to building security tools, so keeping passwords safe is just as important as keeping code secure.<\/p>\n<p>We use\u00a0<a class=\"c-link c-link--underline\" href=\"http:\/\/passwd.team\/\" target=\"_blank\" rel=\"noopener noreferrer\" data-stringify-link=\"http:\/\/passwd.team\" data-sk=\"tooltip_parent\">Passwd.team<\/a>\u00a0because it lets us host everything on our own cloud, so we fully control our credentials. The built-in TOTP 2FA makes it easy for the team to get access without extra hassle, and the audit log helps us track who\u2019s doing what, which is important for compliance.<\/p>\n<p>Overall, it just makes managing passwords simpler and more secure and that\u2019s a big relief when you\u2019re dealing with sensitive work every day.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So you want to write and deploy a smart contract, huh?\u00a0 Go for it and do it as a professional, use the best practices common for the best software out there. There is no need to reinvent the wheel and change processes that work.\u00a0 Sometimes we just need to adjust the tooling &#8211; and that\u2019s what this article is about. Let\u2019s set&hellip;<\/p>\n","protected":false},"author":6,"featured_media":613,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61,10,80,63,103],"tags":[24,88,68,102,104],"class_list":["post-601","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-education","category-ethereum","category-solidity","category-tutorial","category-wake","tag-ethereum","tag-how-to","tag-solidity","tag-tutorial","tag-wake"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/CD-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/12\/CD-600x600.png","author_info":{"display_name":"Jan Kalivoda","author_link":"https:\/\/ackee.xyz\/blog\/author\/jan-kalivoda\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/601","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=601"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/601\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/613"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}