diff --git a/README.md b/README.md index b0cc9fc..4fd2f59 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,28 @@ A library for interacting with Seabug smart contracts via the Cardano Transactio ## Tests Use `spago test` to run the tests. Something like `nix build .#checks..seabug-contracts` can also be used, where `` is something like `x86_64-linux`. + +## Minting + +The minting process currently requires some manual steps. To mint a new NFT: + +- Upload a new image to nft.storage (e.g. using `seabug/scripts/mint-nft.sh`) +- Uncomment [this line](https://github.com/mlabs-haskell/seabug-contracts/blob/cda88824f87e0b961b738c66a428b7ade77454be/index.js#L39) +- Update the image info [here](https://github.com/mlabs-haskell/seabug-contracts/blob/cda88824f87e0b961b738c66a428b7ade77454be/src/Seabug/Seabug.purs#L34) + - Make sure you're using the base36 encoded CID (`mint-nft.sh` prints this out) +- Run `make run-dev` and open the link from the console in chrome; this will trigger the minting + - If Nami/Gero are giving you trouble, this snippet can be used to use a key wallet instead: + ``` + privateKey <- liftM (error "Failed to parse private key") $ + privateKeyFromBytes + =<< hexToRawBytes "" + privateStakeKey <- liftM (error "Failed to parse private stake key") + $ privateKeyFromBytes + =<< hexToRawBytes "" + let wallet = Just $ mkKeyWallet (wrap privateKey) (Just $ wrap privateStakeKey) + ``` + - The secret key can be obtained through e.g. `seabug/scripts/prepare-wallet.sh` (make sure to add ada to that wallet) + - Note you may have to remove the "5820" from the start of the "cborHex" in the skey file + - The stake key will also be necessary for minting, the command `cardano-cli stake-address key-gen --signing-key-file stake.skey --verification-key-file stake.vkey` can be used to get a stake key +- Add the wallet that you minted with as an artist to the + `nft-marketplace-server` database with `admin/create_artist` diff --git a/flake.lock b/flake.lock index 1f35f02..b3cd831 100644 --- a/flake.lock +++ b/flake.lock @@ -32,22 +32,6 @@ "type": "github" } }, - "HTTP_3": { - "flake": false, - "locked": { - "lastModified": 1451647621, - "narHash": "sha256-oHIyw3x0iKBexEo49YeUDV1k74ZtyYKGR2gNJXXRxts=", - "owner": "phadej", - "repo": "HTTP", - "rev": "9bc0996d412fef1787449d841277ef663ad9a915", - "type": "github" - }, - "original": { - "owner": "phadej", - "repo": "HTTP", - "type": "github" - } - }, "Win32-network": { "flake": false, "locked": { @@ -83,23 +67,6 @@ } }, "cabal-32": { - "flake": false, - "locked": { - "lastModified": 1603716527, - "narHash": "sha256-sDbrmur9Zfp4mPKohCD8IDZfXJ0Tjxpmr2R+kg5PpSY=", - "owner": "haskell", - "repo": "cabal", - "rev": "94aaa8e4720081f9c75497e2735b90f6a819b08e", - "type": "github" - }, - "original": { - "owner": "haskell", - "ref": "3.2", - "repo": "cabal", - "type": "github" - } - }, - "cabal-32_2": { "flake": false, "locked": { "lastModified": 1603716527, @@ -116,7 +83,7 @@ "type": "github" } }, - "cabal-32_3": { + "cabal-32_2": { "flake": false, "locked": { "lastModified": 1603716527, @@ -134,23 +101,6 @@ } }, "cabal-34": { - "flake": false, - "locked": { - "lastModified": 1622475795, - "narHash": "sha256-chwTL304Cav+7p38d9mcb+egABWmxo2Aq+xgVBgEb/U=", - "owner": "haskell", - "repo": "cabal", - "rev": "b086c1995cdd616fc8d91f46a21e905cc50a1049", - "type": "github" - }, - "original": { - "owner": "haskell", - "ref": "3.4", - "repo": "cabal", - "type": "github" - } - }, - "cabal-34_2": { "flake": false, "locked": { "lastModified": 1640353650, @@ -167,7 +117,7 @@ "type": "github" } }, - "cabal-34_3": { + "cabal-34_2": { "flake": false, "locked": { "lastModified": 1640353650, @@ -289,11 +239,11 @@ "cardano-configurations": { "flake": false, "locked": { - "lastModified": 1634002394, - "narHash": "sha256-yqw88AbBjBa0VDwXz04+1gV3zXYAaS+/1PNowwmrsJ8=", + "lastModified": 1655361562, + "narHash": "sha256-b/z5RSgqTMQpEUSD4nbrBAr86PcQs+n6EMtn/YPeyj4=", "owner": "input-output-hk", "repo": "cardano-configurations", - "rev": "26b6b6de73f90e4777602b372798bf77addcc321", + "rev": "08e6c0572d5d48049fab521995b29607e0a91a9e", "type": "github" }, "original": { @@ -387,34 +337,6 @@ "type": "github" } }, - "cardano-node-exe": { - "inputs": { - "customConfig": "customConfig", - "haskellNix": "haskellNix", - "iohkNix": "iohkNix", - "nixpkgs": [ - "cardano-transaction-lib", - "cardano-node-exe", - "haskellNix", - "nixpkgs-2105" - ], - "utils": "utils" - }, - "locked": { - "lastModified": 1631803678, - "narHash": "sha256-8BFI16sQGE+ltlA7LcDnh/9V8xjuKcTUd09FyPs1p94=", - "owner": "input-output-hk", - "repo": "cardano-node", - "rev": "ea8b632820db5546b22430bbb5ed8db4a2fef7dd", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "repo": "cardano-node", - "rev": "ea8b632820db5546b22430bbb5ed8db4a2fef7dd", - "type": "github" - } - }, "cardano-node_2": { "flake": false, "locked": { @@ -498,22 +420,6 @@ "type": "github" } }, - "cardano-shell_3": { - "flake": false, - "locked": { - "lastModified": 1608537748, - "narHash": "sha256-PulY1GfiMgKVnBci3ex4ptk2UNYMXqGjJOxcPy2KYT4=", - "owner": "input-output-hk", - "repo": "cardano-shell", - "rev": "9392c75087cb9a3d453998f4230930dea3a95725", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "repo": "cardano-shell", - "type": "github" - } - }, "cardano-transaction-lib": { "inputs": { "Win32-network": "Win32-network", @@ -524,7 +430,6 @@ "cardano-crypto": "cardano-crypto", "cardano-ledger": "cardano-ledger", "cardano-node": "cardano-node", - "cardano-node-exe": "cardano-node-exe", "cardano-prelude": "cardano-prelude", "cardano-wallet": "cardano-wallet", "easy-purescript-nix": "easy-purescript-nix", @@ -549,17 +454,17 @@ "servant-purescript": "servant-purescript" }, "locked": { - "lastModified": 1657293268, - "narHash": "sha256-YTYh5guN2SGm9iUOEhl7nhkmDkgEbhB+8XUiWnB7EAA=", + "lastModified": 1658177328, + "narHash": "sha256-UFAIFcPN7xp85VzYkkU/hJQpN7+Y6qO/BUh/xa3HZTs=", "owner": "Plutonomicon", "repo": "cardano-transaction-lib", - "rev": "6592f4188850ca4b2adab0c593c6a971087a54ba", + "rev": "32194c502e4a068bf99388b05c708f81612d7541", "type": "github" }, "original": { "owner": "Plutonomicon", "repo": "cardano-transaction-lib", - "rev": "6592f4188850ca4b2adab0c593c6a971087a54ba", + "rev": "32194c502e4a068bf99388b05c708f81612d7541", "type": "github" } }, @@ -580,21 +485,6 @@ "type": "github" } }, - "customConfig": { - "locked": { - "lastModified": 1630400035, - "narHash": "sha256-MWaVOCzuFwp09wZIW9iHq5wWen5C69I940N1swZLEQ0=", - "owner": "input-output-hk", - "repo": "empty-flake", - "rev": "2040a05b67bf9a669ce17eca56beb14b4206a99a", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "repo": "empty-flake", - "type": "github" - } - }, "easy-purescript-nix": { "flake": false, "locked": { @@ -710,21 +600,6 @@ } }, "flake-utils": { - "locked": { - "lastModified": 1623875721, - "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { "locked": { "lastModified": 1644229661, "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", @@ -739,7 +614,7 @@ "type": "github" } }, - "flake-utils_3": { + "flake-utils_2": { "locked": { "lastModified": 1644229661, "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", @@ -822,23 +697,6 @@ "type": "github" } }, - "ghc-8.6.5-iohk_3": { - "flake": false, - "locked": { - "lastModified": 1600920045, - "narHash": "sha256-DO6kxJz248djebZLpSzTGD6s8WRpNI9BTwUeOf5RwY8=", - "owner": "input-output-hk", - "repo": "ghc", - "rev": "95713a6ecce4551240da7c96b6176f980af75cae", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "ref": "release/8.6.5-iohk", - "repo": "ghc", - "type": "github" - } - }, "goblins": { "flake": false, "locked": { @@ -876,11 +734,11 @@ "hackage": { "flake": false, "locked": { - "lastModified": 1631668346, - "narHash": "sha256-4dWzl+HoFlXNhaqw4snC3ELBU+6IVBUihuVz41JZi4Y=", + "lastModified": 1650157984, + "narHash": "sha256-hitutrIIn+qINGi6oef53f87we+cp3QNmXSBiCzVU90=", "owner": "input-output-hk", "repo": "hackage.nix", - "rev": "7eb138fdad1ce0a3fba0697d3eba819b185a83d6", + "rev": "2290fdc4d135407896f41ba518a0eae8efaae9c5", "type": "github" }, "original": { @@ -905,46 +763,30 @@ "type": "github" } }, - "hackage_3": { - "flake": false, - "locked": { - "lastModified": 1644887696, - "narHash": "sha256-o4gltv4npUl7+1gEQIcrRqZniwqC9kK8QsPaftlrawc=", - "owner": "input-output-hk", - "repo": "hackage.nix", - "rev": "6ff64aa49b88e75dd6e0bbd2823c2a92c9174fa5", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "repo": "hackage.nix", - "type": "github" - } - }, "haskell-nix": { "inputs": { - "HTTP": "HTTP_2", - "cabal-32": "cabal-32_2", - "cabal-34": "cabal-34_2", + "HTTP": "HTTP", + "cabal-32": "cabal-32", + "cabal-34": "cabal-34", "cabal-36": "cabal-36", - "cardano-shell": "cardano-shell_2", - "flake-utils": "flake-utils_2", - "ghc-8.6.5-iohk": "ghc-8.6.5-iohk_2", - "hackage": "hackage_2", - "hpc-coveralls": "hpc-coveralls_2", + "cardano-shell": "cardano-shell", + "flake-utils": "flake-utils", + "ghc-8.6.5-iohk": "ghc-8.6.5-iohk", + "hackage": "hackage", + "hpc-coveralls": "hpc-coveralls", "hydra": "hydra", - "nix-tools": "nix-tools_2", + "nix-tools": "nix-tools", "nixpkgs": [ "cardano-transaction-lib", "haskell-nix", "nixpkgs-unstable" ], - "nixpkgs-2003": "nixpkgs-2003_2", - "nixpkgs-2105": "nixpkgs-2105_2", + "nixpkgs-2003": "nixpkgs-2003", + "nixpkgs-2105": "nixpkgs-2105", "nixpkgs-2111": "nixpkgs-2111", - "nixpkgs-unstable": "nixpkgs-unstable_2", - "old-ghc-nix": "old-ghc-nix_2", - "stackage": "stackage_2" + "nixpkgs-unstable": "nixpkgs-unstable", + "old-ghc-nix": "old-ghc-nix", + "stackage": "stackage" }, "locked": { "lastModified": 1650194184, @@ -963,29 +805,29 @@ }, "haskell-nix_2": { "inputs": { - "HTTP": "HTTP_3", - "cabal-32": "cabal-32_3", - "cabal-34": "cabal-34_3", + "HTTP": "HTTP_2", + "cabal-32": "cabal-32_2", + "cabal-34": "cabal-34_2", "cabal-36": "cabal-36_2", - "cardano-shell": "cardano-shell_3", - "flake-utils": "flake-utils_3", - "ghc-8.6.5-iohk": "ghc-8.6.5-iohk_3", - "hackage": "hackage_3", - "hpc-coveralls": "hpc-coveralls_3", + "cardano-shell": "cardano-shell_2", + "flake-utils": "flake-utils_2", + "ghc-8.6.5-iohk": "ghc-8.6.5-iohk_2", + "hackage": "hackage_2", + "hpc-coveralls": "hpc-coveralls_2", "hydra": "hydra_2", - "nix-tools": "nix-tools_3", + "nix-tools": "nix-tools_2", "nixpkgs": [ "cardano-transaction-lib", "ogmios", "haskell-nix", "nixpkgs-unstable" ], - "nixpkgs-2003": "nixpkgs-2003_3", - "nixpkgs-2105": "nixpkgs-2105_3", + "nixpkgs-2003": "nixpkgs-2003_2", + "nixpkgs-2105": "nixpkgs-2105_2", "nixpkgs-2111": "nixpkgs-2111_2", - "nixpkgs-unstable": "nixpkgs-unstable_3", - "old-ghc-nix": "old-ghc-nix_3", - "stackage": "stackage_3" + "nixpkgs-unstable": "nixpkgs-unstable_2", + "old-ghc-nix": "old-ghc-nix_2", + "stackage": "stackage_2" }, "locked": { "lastModified": 1650194184, @@ -1002,43 +844,6 @@ "type": "github" } }, - "haskellNix": { - "inputs": { - "HTTP": "HTTP", - "cabal-32": "cabal-32", - "cabal-34": "cabal-34", - "cardano-shell": "cardano-shell", - "flake-utils": "flake-utils", - "ghc-8.6.5-iohk": "ghc-8.6.5-iohk", - "hackage": "hackage", - "hpc-coveralls": "hpc-coveralls", - "nix-tools": "nix-tools", - "nixpkgs": [ - "cardano-transaction-lib", - "cardano-node-exe", - "nixpkgs" - ], - "nixpkgs-2003": "nixpkgs-2003", - "nixpkgs-2009": "nixpkgs-2009", - "nixpkgs-2105": "nixpkgs-2105", - "nixpkgs-unstable": "nixpkgs-unstable", - "old-ghc-nix": "old-ghc-nix", - "stackage": "stackage" - }, - "locked": { - "lastModified": 1631703614, - "narHash": "sha256-XYC0M96V9oQTGq1TSIQTVwkA+SrUqE4o6kUZo4iO8Z4=", - "owner": "input-output-hk", - "repo": "haskell.nix", - "rev": "19052d83fda811dd39216e3fc197c980abd037fd", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "repo": "haskell.nix", - "type": "github" - } - }, "hedgehog-extras": { "flake": false, "locked": { @@ -1122,22 +927,6 @@ "type": "github" } }, - "hpc-coveralls_3": { - "flake": false, - "locked": { - "lastModified": 1607498076, - "narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=", - "owner": "sevanspowell", - "repo": "hpc-coveralls", - "rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430", - "type": "github" - }, - "original": { - "owner": "sevanspowell", - "repo": "hpc-coveralls", - "type": "github" - } - }, "hydra": { "inputs": { "nix": "nix", @@ -1164,7 +953,6 @@ }, "hydra_2": { "inputs": { - "newNixpkgs": "newNixpkgs", "nix": "nix_2", "nixpkgs": [ "cardano-transaction-lib", @@ -1176,11 +964,11 @@ ] }, "locked": { - "lastModified": 1657142040, - "narHash": "sha256-QetBWv3AB+mDGJH7CbbLp5LTMtKPG7TuOVyFpHmZXog=", + "lastModified": 1646878427, + "narHash": "sha256-KtbrofMtN8GlM7D+n90kixr7QpSlVmdN+vK5CA/aRzc=", "owner": "NixOS", "repo": "hydra", - "rev": "bf50ae0d36be9a7d7d65457cc19245f4da3d8e5d", + "rev": "28b682b85b7efc5cf7974065792a1f22203a5927", "type": "github" }, "original": { @@ -1276,28 +1064,6 @@ "type": "github" } }, - "iohkNix": { - "inputs": { - "nixpkgs": [ - "cardano-transaction-lib", - "cardano-node-exe", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1631778944, - "narHash": "sha256-N5eCcUYtZ5kUOl/JJGjx6ZzhA3uIn1itDRTiRV+3jLw=", - "owner": "input-output-hk", - "repo": "iohk-nix", - "rev": "db2c75a09c696271194bb3ef25ec8e9839b594b7", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "repo": "iohk-nix", - "type": "github" - } - }, "lowdown-src": { "flake": false, "locked": { @@ -1330,22 +1096,6 @@ "type": "github" } }, - "newNixpkgs": { - "locked": { - "lastModified": 1647380550, - "narHash": "sha256-909TI9poX7CIUiFx203WL29YON6m/I6k0ExbZvR7bLM=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "6e3ee8957637a60f5072e33d78e05c0f65c54366", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable-small", - "repo": "nixpkgs", - "type": "github" - } - }, "nix": { "inputs": { "lowdown-src": "lowdown-src", @@ -1370,11 +1120,11 @@ "nix-tools": { "flake": false, "locked": { - "lastModified": 1626997434, - "narHash": "sha256-1judQmP298ao6cGUNxcGhcAXHOnA9qSLvWk/ZtoUL7w=", + "lastModified": 1649424170, + "narHash": "sha256-XgKXWispvv5RCvZzPb+p7e6Hy3LMuRjafKMl7kXzxGw=", "owner": "input-output-hk", "repo": "nix-tools", - "rev": "c8c5e6a6fbb12a73598d1a434984a36e880ce3cf", + "rev": "e109c94016e3b6e0db7ed413c793e2d4bdb24aa7", "type": "github" }, "original": { @@ -1399,22 +1149,6 @@ "type": "github" } }, - "nix-tools_3": { - "flake": false, - "locked": { - "lastModified": 1644395812, - "narHash": "sha256-BVFk/BEsTLq5MMZvdy3ZYHKfaS3dHrsKh4+tb5t5b58=", - "owner": "input-output-hk", - "repo": "nix-tools", - "rev": "d847c63b99bbec78bf83be2a61dc9f09b8a9ccc1", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "repo": "nix-tools", - "type": "github" - } - }, "nix_2": { "inputs": { "lowdown-src": "lowdown-src_2", @@ -1422,16 +1156,16 @@ "nixpkgs-regression": "nixpkgs-regression_2" }, "locked": { - "lastModified": 1654014617, - "narHash": "sha256-qNL3lQPBsnStkru3j1ajN/H+knXI+X3dku8/dBfSw3g=", + "lastModified": 1643066034, + "narHash": "sha256-xEPeMcNJVOeZtoN+d+aRwolpW8mFSEQx76HTRdlhPhg=", "owner": "NixOS", "repo": "nix", - "rev": "624e38aa43f304fbb78b4779172809add042b513", + "rev": "a1cd7e58606a41fcf62bf8637804cf8306f17f62", "type": "github" }, "original": { "owner": "NixOS", - "ref": "2.9.1", + "ref": "2.6.0", "repo": "nix", "type": "github" } @@ -1483,45 +1217,13 @@ "type": "github" } }, - "nixpkgs-2003_3": { - "locked": { - "lastModified": 1620055814, - "narHash": "sha256-8LEHoYSJiL901bTMVatq+rf8y7QtWuZhwwpKE2fyaRY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "1db42b7fe3878f3f5f7a4f2dc210772fd080e205", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-20.03-darwin", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-2009": { - "locked": { - "lastModified": 1624271064, - "narHash": "sha256-qns/uRW7MR2EfVf6VEeLgCsCp7pIOjDeR44JzTF09MA=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "46d1c3f28ca991601a53e9a14fdd53fcd3dd8416", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-20.09-darwin", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs-2105": { "locked": { - "lastModified": 1630481079, - "narHash": "sha256-leWXLchbAbqOlLT6tju631G40SzQWPqaAXQG3zH1Imw=", + "lastModified": 1645296114, + "narHash": "sha256-y53N7TyIkXsjMpOG7RhvqJFGDacLs9HlyHeSTBioqYU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "110a2c9ebbf5d4a94486854f18a37a938cfacbbb", + "rev": "530a53dcbc9437363471167a5e4762c5fcfa34a1", "type": "github" }, "original": { @@ -1547,22 +1249,6 @@ "type": "github" } }, - "nixpkgs-2105_3": { - "locked": { - "lastModified": 1642244250, - "narHash": "sha256-vWpUEqQdVP4srj+/YLJRTN9vjpTs4je0cdWKXPbDItc=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "0fd9ee1aa36ce865ad273f4f07fdc093adeb5c00", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-21.05-darwin", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs-2111": { "locked": { "lastModified": 1648744337, @@ -1581,11 +1267,11 @@ }, "nixpkgs-2111_2": { "locked": { - "lastModified": 1644510859, - "narHash": "sha256-xjpVvL5ecbyi0vxtVl/Fh9bwGlMbw3S06zE5nUzFB8A=", + "lastModified": 1648744337, + "narHash": "sha256-bYe1dFJAXovjqiaPKrmAbSBEK5KUkgwVaZcTbSoJ7hg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0d1d5d7e3679fec9d07f2eb804d9f9fdb98378d3", + "rev": "0a58eebd8ec65ffdef2ce9562784123a73922052", "type": "github" }, "original": { @@ -1627,11 +1313,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1628785280, - "narHash": "sha256-2B5eMrEr6O8ff2aQNeVxTB+9WrGE80OB4+oM6T7fOcc=", + "lastModified": 1648219316, + "narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6525bbc06a39f26750ad8ee0d40000ddfdc24acb", + "rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634", "type": "github" }, "original": { @@ -1657,22 +1343,6 @@ "type": "github" } }, - "nixpkgs-unstable_3": { - "locked": { - "lastModified": 1644486793, - "narHash": "sha256-EeijR4guVHgVv+JpOX3cQO+1XdrkJfGmiJ9XVsVU530=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "1882c6b7368fd284ad01b0a5b5601ef136321292", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs_2": { "locked": { "lastModified": 1647122627, @@ -1688,11 +1358,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1645296114, - "narHash": "sha256-y53N7TyIkXsjMpOG7RhvqJFGDacLs9HlyHeSTBioqYU=", + "lastModified": 1632864508, + "narHash": "sha256-d127FIvGR41XbVRDPVvozUPQ/uRHbHwvfyKHwEt5xFM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "530a53dcbc9437363471167a5e4762c5fcfa34a1", + "rev": "82891b5e2c2359d7e58d08849e4c89511ab94234", "type": "github" }, "original": { @@ -1703,12 +1373,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1657177452, - "narHash": "sha256-CojBqno3Zbw9/788+kCjRXXornpc4jJGC6RYvTYdVkg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "5cbfadba693e0453f3a4090e83fbf845e18d184b", - "type": "github" + "lastModified": 1647122627, + "narHash": "sha256-w4hGsXYyMgJAQRSBxh7O6AAsawJSbudCxfQXhDRhwPQ=", + "path": "/nix/store/s6wigis38dnikj5y92jrrj7ywc38b78g-source", + "rev": "0f85665118d850aae5164d385d24783d0b16cf1b", + "type": "path" }, "original": { "id": "nixpkgs", @@ -1832,23 +1501,6 @@ "type": "github" } }, - "old-ghc-nix_3": { - "flake": false, - "locked": { - "lastModified": 1631092763, - "narHash": "sha256-sIKgO+z7tj4lw3u6oBZxqIhDrzSkvpHtv0Kki+lh9Fg=", - "owner": "angerman", - "repo": "old-ghc-nix", - "rev": "af48a7a7353e418119b6dfe3cd1463a657f342b8", - "type": "github" - }, - "original": { - "owner": "angerman", - "ref": "master", - "repo": "old-ghc-nix", - "type": "github" - } - }, "optparse-applicative": { "flake": false, "locked": { @@ -1998,11 +1650,11 @@ "stackage": { "flake": false, "locked": { - "lastModified": 1631495632, - "narHash": "sha256-jnkmC3PqnRpM4y74b4ZxgD+MTpz3ovxoU99TBCNRDP0=", + "lastModified": 1650158092, + "narHash": "sha256-uQ/TEFcce0bKmYcoBziDhYYzCDmhPsjC5WgsJjpd9wA=", "owner": "input-output-hk", "repo": "stackage.nix", - "rev": "3f43e2e72e0853e911497277ec094933892718a9", + "rev": "adc7f942e756b382a7a833520ebef6dfc859af8e", "type": "github" }, "original": { @@ -2027,22 +1679,6 @@ "type": "github" } }, - "stackage_3": { - "flake": false, - "locked": { - "lastModified": 1644887829, - "narHash": "sha256-tjUXJpqB7MMnqM4FF5cdtZipfratUcTKRQVA6F77sEQ=", - "owner": "input-output-hk", - "repo": "stackage.nix", - "rev": "db8bdef6588cf4f38e6069075ba76f0024381f68", - "type": "github" - }, - "original": { - "owner": "input-output-hk", - "repo": "stackage.nix", - "type": "github" - } - }, "typed-protocols": { "flake": false, "locked": { @@ -2062,11 +1698,11 @@ }, "unstable_nixpkgs": { "locked": { - "lastModified": 1657211021, - "narHash": "sha256-rTQX2TgrFYjl3leui/jPkUptzjy8nIW3rNenO4PhfLk=", + "lastModified": 1653307806, + "narHash": "sha256-VPej3GE4IBMwYnXRfbiVqMWKa32+ysuvbHRkQXD0gTw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "98472c0467e56d143b2f97a669eddefb7cf99b19", + "rev": "9d7aff488a8f9429d9e6cd82c10dffbf21907fb1", "type": "github" }, "original": { @@ -2075,21 +1711,6 @@ "type": "github" } }, - "utils": { - "locked": { - "lastModified": 1623875721, - "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "wai-routes": { "flake": false, "locked": { diff --git a/flake.nix b/flake.nix index bf15a1c..a9d20aa 100644 --- a/flake.nix +++ b/flake.nix @@ -11,9 +11,9 @@ owner = "Plutonomicon"; repo = "cardano-transaction-lib"; # should be same rev as in packages.dhall - # Oh update, do `spago2nix generate` - # https://github.com/Plutonomicon/cardano-transaction-lib/pull/702/commits/6592f4188850ca4b2adab0c593c6a971087a54ba - rev = "6592f4188850ca4b2adab0c593c6a971087a54ba"; + # To update, do `spago2nix generate` + # calum/metadata-invalid-char-fix + rev = "32194c502e4a068bf99388b05c708f81612d7541"; }; nixpkgs.follows = "cardano-transaction-lib/nixpkgs"; }; @@ -24,7 +24,7 @@ perSystem = nixpkgs.lib.genAttrs defaultSystems; nixpkgsFor = system: import nixpkgs { inherit system; - overlays = [ cardano-transaction-lib.overlay.${system} ]; + overlays = [ cardano-transaction-lib.overlay ]; }; psProjectFor = system: let @@ -43,7 +43,7 @@ }; in { - defaultPackage = perSystem (system: self.packages.${system}.seabug-contracts); + defaultPackage = perSystem (system: self.packages.${system}.seabug-contracts-bundle-web); packages = perSystem (system: let diff --git a/index.js b/index.js index 38e5251..53339d7 100644 --- a/index.js +++ b/index.js @@ -40,3 +40,6 @@ exports.getWalletBalance = async () => { const sb = await seabug; return sb.getWalletBalance(); }; + +// Uncomment this for manually minting new tokens (see README) +// seabug.then((sb) => sb.mint().then(() => console.log("Done"))) diff --git a/packages.dhall b/packages.dhall index 36f0a64..a67b853 100644 --- a/packages.dhall +++ b/packages.dhall @@ -149,7 +149,7 @@ let additions = , "untagged-union" ] , repo = "https://github.com/mlabs-haskell/purescript-aeson.git" - , version = "69bd18c4a9cffdebc45c55d2448740721a91854c" + , version = "286862a975f4bafbef15540c365bbbb0480e0bf7" } , aeson-helpers = { dependencies = @@ -328,7 +328,11 @@ let additions = ] , repo = "https://github.com/Plutonomicon/cardano-transaction-lib.git" -- should be same rev as in flake.nix - , version = "6592f4188850ca4b2adab0c593c6a971087a54ba" + -- https://github.com/Plutonomicon/cardano-transaction-lib/pull/696 + -- PR: Return error if no utxo is specified for a tx input & Fix transaction inputs locking + -- Commit is from our branch calum/metadata-invalid-char-fix which is based off this PR and + -- includes a small fix to get the build working. Also updated to include `awaitTxConfirmed`. + , version = "32194c502e4a068bf99388b05c708f81612d7541" } } in upstream // additions diff --git a/spago-packages.nix b/spago-packages.nix index 10b1e82..f2ff121 100644 --- a/spago-packages.nix +++ b/spago-packages.nix @@ -7,11 +7,11 @@ let "aeson" = pkgs.stdenv.mkDerivation { name = "aeson"; - version = "69bd18c4a9cffdebc45c55d2448740721a91854c"; + version = "286862a975f4bafbef15540c365bbbb0480e0bf7"; src = pkgs.fetchgit { url = "https://github.com/mlabs-haskell/purescript-aeson.git"; - rev = "69bd18c4a9cffdebc45c55d2448740721a91854c"; - sha256 = "1khn834wsqgf80p8xjyw6z06dhj8vknj7lhpm5dj44nqlaj8qhqb"; + rev = "286862a975f4bafbef15540c365bbbb0480e0bf7"; + sha256 = "1d5h9n9f2qk8hjzqmhjfzwf86x3y60g3cm13gyvm5aaqjraaksvg"; }; phases = "installPhase"; installPhase = "ln -s $src $out"; @@ -199,11 +199,11 @@ let "cardano-transaction-lib" = pkgs.stdenv.mkDerivation { name = "cardano-transaction-lib"; - version = "6592f4188850ca4b2adab0c593c6a971087a54ba"; + version = "32194c502e4a068bf99388b05c708f81612d7541"; src = pkgs.fetchgit { url = "https://github.com/Plutonomicon/cardano-transaction-lib.git"; - rev = "6592f4188850ca4b2adab0c593c6a971087a54ba"; - sha256 = "000hgdq5l8kmy5z10vh49072c6cygcci43i5ysk23ncd1gk22dk1"; + rev = "32194c502e4a068bf99388b05c708f81612d7541"; + sha256 = "0fv5qynwazs80nzs7slqpwvjk5447x2r5n2wwmy1mvydqcahhl2h"; }; phases = "installPhase"; installPhase = "ln -s $src $out"; diff --git a/spago.dhall b/spago.dhall index b6a2dd9..326bced 100644 --- a/spago.dhall +++ b/spago.dhall @@ -27,6 +27,7 @@ You can edit this file as you like. , "monad-logger" , "mote" , "newtype" + , "nonempty" , "nullable" , "ordered-collections" , "parallel" diff --git a/src/Seabug/CallContract.purs b/src/Seabug/CallContract.purs index b308ff4..9a4a4d5 100644 --- a/src/Seabug/CallContract.purs +++ b/src/Seabug/CallContract.purs @@ -3,11 +3,11 @@ module Seabug.CallContract , callMarketPlaceBuyTest , callMarketPlaceFetchNft , callMarketPlaceListNft + , callMint ) where -import Contract.Prelude +import Contract.Prelude hiding (null) -import Cardano.Types.Value as Cardano.Types.Value import Contract.Address (Slot(Slot)) import Contract.Monad ( ConfigParams(ConfigParams) @@ -21,6 +21,7 @@ import Contract.Prim.ByteArray (byteArrayToHex, hexToByteArray) import Contract.Transaction ( TransactionInput(..) , TransactionOutput(TransactionOutput) + , awaitTxConfirmed ) import Contract.Value ( CurrencySymbol @@ -46,14 +47,18 @@ import Effect.Class (liftEffect) import Effect.Exception (Error) import Partial.Unsafe (unsafePartial) import Plutus.Conversion (fromPlutusAddress) +import Seabug.Contract.CnftMint (mintCnft) import Seabug.Contract.Common (NftResult) import Seabug.Contract.MarketPlaceBuy (marketplaceBuy) import Seabug.Contract.MarketPlaceFetchNft (marketPlaceFetchNft) import Seabug.Contract.MarketPlaceListNft (marketPlaceListNft) +import Seabug.Contract.Mint (mintWithCollection) import Seabug.Metadata.Share (unShare) import Seabug.Metadata.Types (SeabugMetadata(SeabugMetadata)) import Seabug.Types - ( NftCollection(NftCollection) + ( MintCnftParams + , MintParams + , NftCollection(NftCollection) , NftData(NftData) , NftId(NftId) ) @@ -72,6 +77,23 @@ import Wallet (mkNamiWalletAff) callMarketPlaceBuyTest :: String -> Effect (Promise String) callMarketPlaceBuyTest = Promise.fromAff <<< pure +callMint :: ContractConfiguration -> MintArgs -> Effect (Promise Unit) +callMint cfg args = Promise.fromAff do + contractConfig <- buildContractConfig cfg + mintCnftParams /\ mintParams <- liftEffect $ liftEither $ buildMintArgs args + runContract contractConfig $ do + log "Minting cnft..." + txHash /\ cnft <- mintCnft mintCnftParams + log $ "Waiting for confirmation of cnft transaction: " <> show txHash + awaitTxConfirmed txHash + log $ "Cnft transaction confirmed: " <> show txHash + log $ "Minted cnft: " <> show cnft + log "Minting sgNft..." + sgNftTxHash <- mintWithCollection cnft mintParams + log $ "Waiting for confirmation of nft transaction: " <> show sgNftTxHash + awaitTxConfirmed sgNftTxHash + log $ "Nft transaction confirmed: " <> show sgNftTxHash + callMarketPlaceFetchNft :: ContractConfiguration -> TransactionInputOut @@ -163,6 +185,14 @@ type ListNftResultOut = } } +type MintArgs = + { imageUri :: String + , tokenNameString :: String + , name :: String + , description :: String + , price :: BigInt -- Natural + } + buildContractConfig :: ContractConfiguration -> Aff (ContractConfig (projectId :: String)) buildContractConfig cfg = do @@ -243,8 +273,7 @@ buildNftList convertSeabugMetaData (SeabugMetadata m) = { policyId: scriptHashToBech32Unsafe "policy_vkh" $ unwrap m.policyId -- or the prefix should just be 'script' , mintPolicy: byteArrayToHex m.mintPolicy - , collectionNftCS: byteArrayToHex $ Cardano.Types.Value.getCurrencySymbol $ - m.collectionNftCS + , collectionNftCS: byteArrayToHex $ getCurrencySymbol m.collectionNftCS , collectionNftTN: byteArrayToHex $ getTokenName m.collectionNftTN , lockingScript: scriptHashToBech32Unsafe "script" $ unwrap m.lockingScript , authorPkh: byteArrayToHex $ unwrap $ ed25519KeyHashToBytes $ unwrap @@ -314,6 +343,29 @@ buildNftData { nftCollectionArgs, nftIdArgs } = do , daoShare } +buildMintArgs :: MintArgs -> Either Error (MintCnftParams /\ MintParams) +buildMintArgs + { imageUri + , tokenNameString + , name + , description + , price + } = do + price' <- note (error $ "Invalid price: " <> show price) + $ Nat.fromBigInt price + let + mintCnftParams = wrap { imageUri, tokenNameString, name, description } + -- TODO: Put these hard coded params in a better place + mintParams = wrap + { authorShare: Nat.fromInt' 500 + , daoShare: Nat.fromInt' 500 + , price: price' + , lockLockup: BigInt.fromInt 5 + , lockLockupEnd: Slot $ BigNum.fromInt 5 + , feeVaultKeys: [] + } + pure (mintCnftParams /\ mintParams) + buildTransactionInput :: TransactionInputOut -> Either Error TransactionInput buildTransactionInput input = do transactionId <- diff --git a/src/Seabug/CnftMintPolicy.js b/src/Seabug/CnftMintPolicy.js new file mode 100644 index 0000000..25a7ba9 --- /dev/null +++ b/src/Seabug/CnftMintPolicy.js @@ -0,0 +1,6 @@ +exports._cnftMintingPolicy = { + mintingPolicy: { + getMintingPolicy: +"5908be010000323322333222323233223322323233322232333222323333333322222222323332223233332222323233223233322232323233223322323233333222223322332233223322332233223322332223003300200122232325335302f330050043333573466e1cd55cea8012400046601464646464646464646464646666ae68cdc39aab9d500a480008cccccccccc060cd40988c8c8cccd5cd19b8735573aa004900011980f181b1aba15002302b357426ae8940088c98d4c158cd5ce02d02b82a82a09aab9e5001137540026ae854028cd409809cd5d0a804999aa816bae502c35742a010666aa05aeb940b0d5d0a80399a81301f9aba15006335026335505004875a6ae854014c8c8c8cccd5cd19b8735573aa0049000119a8101919191999ab9a3370e6aae7540092000233502833503e75a6ae854008c10cd5d09aba25002232635305a3357380bc0b60b20b026aae7940044dd50009aba150023232323333573466e1cd55cea80124000466a04c66a07ceb4d5d0a80118219aba135744a004464c6a60b466ae7017816c1641604d55cf280089baa001357426ae8940088c98d4c158cd5ce02d02b82a82a09aab9e5001137540026ae854010cd4099d71aba15003335026335505075c40026ae854008c0d4d5d09aba2500223263530523357380ac0a60a20a026ae8940044d5d1280089aba25001135744a00226ae8940044d5d1280089aba25001135744a00226aae7940044dd50009aba150023232323333573466e1d400520062301d3037357426aae79400c8cccd5cd19b875002480108c070c104d5d09aab9e500423333573466e1d400d20022301c302c357426aae7940148cccd5cd19b875004480008c07cdd71aba135573ca00c464c6a609a66ae7014413813012c1281241204d55cea80089baa001357426ae8940088c98d4c118cd5ce025023822822082309931a982299ab9c49010350543500046044135573ca00226ea80048c8894cd4c0b8ccd54c12448004c8cd413c88ccd4d402000c88008008004d4d401800488004cd4018894cd4c0c000840c840040bc8cc894cd4c0c4ccd5cd19b8f35302800222002353028001220020330321333573466e1cd4c0a000888004d4c0a0004880040cc0c840c8d4c03000488008010d4c024d4c01c00488008888888888802840c04cd5ce249115554784f206e6f7420636f6e73756d65640002f30210011221233001003002120012212330010030022001222222222212333333333300100b00a00900800700600500400300220012212330010030022001122123300100300212001122123300100300212001122123300100300212001212222300400521222230030052122223002005212222300100520011232230023758002640026aa070446666aae7c004940e08cd40dcc010d5d080118019aba200203023232323333573466e1cd55cea801a4000466600e6464646666ae68cdc39aab9d5002480008cc034c0b8d5d0a80119a8080151aba135744a004464c6a606866ae700e00d40cc0c84d55cf280089baa00135742a006666aa016eb94028d5d0a80119a8063ae357426ae8940088c98d4c0c0cd5ce01a01881781709aba25001135573ca00226ea800488848ccc00401000c00880048848cc00400c00880044cd54005d73ad112232230023756002640026aa06444646666aae7c008940cc8cd40c8cd540b8c018d55cea80118029aab9e500230043574400605626ae84004488c8c8cccd5cd19b875001480008d4020c014d5d09aab9e500323333573466e1d4009200225008232635302a33573805c05605205004e26aae7540044dd5000890911801001889100089000919191999ab9a3370e6aae7540092000233006300735742a0046eb4d5d09aba25002232635302433573805004a04604426aae7940044dd500091091980080180110009191999ab9a3370e6aae75400520002375c6ae84d55cf280111931a981019ab9c02402101f01e1375400224464646666ae68cdc3a800a40084a00e46666ae68cdc3a8012400446a014600c6ae84d55cf280211999ab9a3370ea00690001280511931a981199ab9c02702402202102001f135573aa00226ea8004484888c00c0104488800844888004480048c8cccd5cd19b8750014800880188cccd5cd19b8750024800080188c98d4c06ccd5ce00f80e00d00c80c09aab9d37540022440042440024002464646464646666ae68cdc3a800a4018401646666ae68cdc3a80124014401a46666ae68cdc3a801a40104660166eb8d5d0a8029bad357426ae8940148cccd5cd19b875004480188cc034dd71aba15007375c6ae84d5d1280391999ab9a3370ea00a9002119809180a1aba15009375c6ae84d5d1280491999ab9a3370ea00c90011180a180a9aba135573ca01646666ae68cdc3a803a400046026602c6ae84d55cf280611931a981019ab9c02402101f01e01d01c01b01a019018135573aa00826aae79400c4d55cf280109aab9e500113754002424444444600e01044244444446600c012010424444444600a010244444440082444444400644244444446600401201044244444446600201201040024646464646666ae68cdc3a800a400446660106eb4d5d0a8021bad35742a0066eb4d5d09aba2500323333573466e1d400920002300a300b357426aae7940188c98d4c044cd5ce00a80900800780709aab9d5003135744a00226aae7940044dd5000909118010019110911998008028020019000919191999ab9a3370ea0029001118031bae357426aae79400c8cccd5cd19b875002480008c020dd71aba135573ca008464c6a601666ae7003c0300280240204d55cea80089baa001212230020032122300100320011122232323333573466e1cd55cea80124000466aa016600c6ae854008c014d5d09aba25002232635300833573801801200e00c26aae7940044dd5000a4c240024002224424660020060042240029210350543100320013550062211222533535006001135350090032200122133353500b0052200230040023335530071200100500400111220021221223300100400312001122123300100300212001112323001001223300330020020011", + } +} diff --git a/src/Seabug/CnftMintPolicy.purs b/src/Seabug/CnftMintPolicy.purs new file mode 100644 index 0000000..535db90 --- /dev/null +++ b/src/Seabug/CnftMintPolicy.purs @@ -0,0 +1,24 @@ +module Seabug.CnftMintPolicy (mkCnftMintingPolicy) where + +import Contract.Prelude + +import Contract.Monad (Contract, liftContractE) +import Contract.PlutusData (toData) +import Contract.Scripts (MintingPolicy, applyArgs) +import Contract.Transaction (TransactionInput) +import Data.Argonaut (Json, JsonDecodeError) +import QueryM as QueryM +import Seabug.Helpers (jsonReader) + +mkCnftMintingPolicy + :: forall (r :: Row Type) + . TransactionInput + -> Contract r (Either QueryM.ClientError MintingPolicy) +mkCnftMintingPolicy oref = do + p <- liftContractE cnftMintingPolicy + applyArgs p [ toData oref ] + +cnftMintingPolicy :: Either JsonDecodeError MintingPolicy +cnftMintingPolicy = jsonReader "mintingPolicy" _cnftMintingPolicy + +foreign import _cnftMintingPolicy :: Json diff --git a/src/Seabug/Contract/CnftMint.purs b/src/Seabug/Contract/CnftMint.purs new file mode 100644 index 0000000..bace96f --- /dev/null +++ b/src/Seabug/Contract/CnftMint.purs @@ -0,0 +1,85 @@ +module Seabug.Contract.CnftMint where + +import Contract.Prelude + +import Contract.Address + ( getNetworkId + , ownPaymentPubKeyHash + , ownStakePubKeyHash + , payPubKeyHashBaseAddress + ) +import Contract.AuxiliaryData (setTxMetadata) +import Contract.Monad (Contract, liftContractM, liftedE, liftedM) +import Contract.Prim.ByteArray (hexToByteArray) +import Contract.ScriptLookups as Lookups +import Contract.Scripts (mintingPolicyHash) +import Contract.Transaction (TransactionHash, balanceAndSignTxE, submit) +import Contract.TxConstraints as Constraints +import Contract.Utxos (utxosAt) +import Contract.Value + ( CurrencySymbol + , TokenName + , mkTokenName + , scriptCurrencySymbol + , singleton + ) +import Data.Array (head) +import Data.Map as Map +import Data.NonEmpty as NonEmpty +import Metadata.Cip25 (Cip25Metadata(..), Cip25MetadataEntry(..)) +import Seabug.CnftMintPolicy (mkCnftMintingPolicy) +import Seabug.Types (MintCnftParams(..)) + +-- | Mint a collection NFT +mintCnft + :: forall (r :: Row Type) + . MintCnftParams + -> Contract r (TransactionHash /\ (CurrencySymbol /\ TokenName)) +mintCnft (MintCnftParams params) = do + owner <- liftedM "Cannot get PaymentPubKeyHash" ownPaymentPubKeyHash + ownerStake <- liftedM "Cannot get StakePubKeyHash" ownStakePubKeyHash + networkId <- getNetworkId + addr <- liftContractM "Cannot get user address" $ + payPubKeyHashBaseAddress networkId owner ownerStake + utxos <- liftedM "Cannot get user utxos" $ utxosAt addr + oref /\ _ <- liftContractM "Cannot find user utxo" + $ head + $ Map.toUnfoldableUnordered (unwrap utxos) + policy <- liftedE $ mkCnftMintingPolicy oref + curr <- liftedM "Could not get currency symbol" $ liftAff $ + scriptCurrencySymbol policy + -- TODO: figure out how to encode the token name (base64 maybe) + tn <- liftContractM "Invalid token name" + $ mkTokenName + =<< hexToByteArray params.tokenNameString + let + value = singleton curr tn one + lookups = mconcat + [ Lookups.mintingPolicy policy + , Lookups.unspentOutputs $ unwrap utxos + ] + + constraints :: Constraints.TxConstraints Unit Unit + constraints = mconcat + [ Constraints.mustMintValue value + , Constraints.mustSpendPubKeyOutput oref + , Constraints.mustPayToPubKeyAddress owner ownerStake value + ] + unbalancedTx <- liftedE $ Lookups.mkUnbalancedTx lookups constraints + policyHash <- liftedM "Could not get minting policy hash" $ liftAff $ + mintingPolicyHash policy + unbalancedTxWithMetadata <- setTxMetadata unbalancedTx $ Cip25Metadata + [ Cip25MetadataEntry + { policyId: policyHash + , assetName: tn + , imageUris: NonEmpty.singleton params.imageUri + , mediaType: Nothing + , description: [ params.name, params.description ] + , files: [] + } + ] + signedTx <- liftedE $ balanceAndSignTxE unbalancedTxWithMetadata + transactionHash <- submit signedTx + log $ "CNFT Mint transaction successfully submitted with hash: " + <> show transactionHash + pure (transactionHash /\ curr /\ tn) diff --git a/src/Seabug/Contract/MarketPlaceBuy.purs b/src/Seabug/Contract/MarketPlaceBuy.purs index 6ccaa7b..2d04a2f 100644 --- a/src/Seabug/Contract/MarketPlaceBuy.purs +++ b/src/Seabug/Contract/MarketPlaceBuy.purs @@ -5,11 +5,15 @@ module Seabug.Contract.MarketPlaceBuy import Contract.Prelude -import Contract.Address - ( getNetworkId - , ownPaymentPubKeyHash +import Contract.Address (getNetworkId, ownPaymentPubKeyHash) +import Contract.Monad (Contract, liftContractE, liftContractM, liftedE, liftedM) +import Contract.Numeric.Natural (toBigInt) +import Contract.PlutusData + ( Datum(Datum) + , Redeemer(Redeemer) + , toData + , unitRedeemer ) - import Contract.ScriptLookups (UnattachedUnbalancedTx, mkUnbalancedTx) import Contract.ScriptLookups ( mintingPolicy @@ -18,21 +22,7 @@ import Contract.ScriptLookups , typedValidatorLookups , unspentOutputs ) as ScriptLookups -import Contract.Monad - ( Contract - , liftContractM - , liftContractE - , liftedE - , liftedM - ) -import Contract.Numeric.Natural (toBigInt) -import Contract.PlutusData - ( Datum(Datum) - , Redeemer(Redeemer) - , toData - , unitRedeemer - ) -import Contract.Scripts (applyArgs, typedValidatorEnterpriseAddress) +import Contract.Scripts (typedValidatorEnterpriseAddress) import Contract.Transaction ( TransactionOutput(TransactionOutput) , balanceAndSignTxE @@ -53,19 +43,16 @@ import Data.Bifunctor (lmap) import Data.BigInt (BigInt, fromInt) import Data.Map (insert, toUnfoldable) import Data.String.Common (joinWith) +import Seabug.Contract.Util (minAdaOnlyUTxOValue, setSeabugMetadata) import Seabug.MarketPlace (marketplaceValidator) -import Seabug.MintingPolicy (mintingPolicy) -import Seabug.Token (mkTokenName) +import Seabug.MintingPolicy (mkMintingPolicy, mkTokenName) import Seabug.Types ( MarketplaceDatum(MarketplaceDatum) , MintAct(ChangeOwner) - , NftData(NftData) + , NftData(..) , NftId(NftId) ) -minAdaOnlyUTxOValue :: BigInt -minAdaOnlyUTxOValue = fromInt 1_000_000 - -- TODO docstring marketplaceBuy :: forall (r :: Row Type). NftData -> Contract r Unit marketplaceBuy nftData = do @@ -104,7 +91,6 @@ mkMarketplaceTx (NftData nftData) = do let nftCollection = unwrap nftData.nftCollection pkh <- liftedM "marketplaceBuy: Cannot get PaymentPubKeyHash" ownPaymentPubKeyHash - policy' <- liftedE $ pure mintingPolicy log $ "policy args: " <> joinWith "; " [ "collectionNftCs: " <> show nftCollection.collectionNftCs , "lockingScript: " <> show nftCollection.lockingScript @@ -113,14 +99,7 @@ mkMarketplaceTx (NftData nftData) = do , "daoScript: " <> show nftCollection.daoScript , "daoShare: " <> show nftCollection.daoShare ] - policy <- liftedE $ applyArgs policy' - [ toData nftCollection.collectionNftCs - , toData nftCollection.lockingScript - , toData nftCollection.author - , toData nftCollection.authorShare - , toData nftCollection.daoScript - , toData nftCollection.daoShare - ] + policy <- liftedE $ mkMintingPolicy $ wrap nftCollection curr <- liftedM "marketplaceBuy: Cannot get CurrencySymbol" $ liftAff @@ -228,4 +207,7 @@ mkMarketplaceTx (NftData nftData) = do -- the datums and redeemers will be reattached using a server with redeemers -- reindexed also. txDatumsRedeemerTxIns <- liftedE $ mkUnbalancedTx lookup constraints - pure $ txDatumsRedeemerTxIns /\ curr /\ newName + txWithMetadata <- + setSeabugMetadata (wrap nftData { nftId = newNft }) curr + txDatumsRedeemerTxIns + pure $ txWithMetadata /\ curr /\ newName diff --git a/src/Seabug/Contract/MarketPlaceListNft.purs b/src/Seabug/Contract/MarketPlaceListNft.purs index dfe98bc..b9d66fd 100644 --- a/src/Seabug/Contract/MarketPlaceListNft.purs +++ b/src/Seabug/Contract/MarketPlaceListNft.purs @@ -7,6 +7,7 @@ import Contract.Prelude import Contract.Address (getNetworkId, typedValidatorEnterpriseAddress) import Contract.Monad (Contract, liftContractE, liftedM) +import Contract.Numeric.Natural as Natural import Contract.PlutusData (fromData, getDatumsByHashes) import Contract.Transaction (TransactionOutput(TransactionOutput)) import Contract.Utxos (utxosAt) @@ -18,6 +19,7 @@ import Control.Parallel (parTraverse) import Data.Array (catMaybes, mapMaybe) import Data.Map as Map import Seabug.Contract.Common (NftResult) +import Seabug.Contract.Util (minAdaOnlyUTxOValue) import Seabug.MarketPlace (marketplaceValidator) import Seabug.Metadata (getFullSeabugMetadataWithBackoff) import Seabug.Types (MarketplaceDatum(MarketplaceDatum)) @@ -52,5 +54,11 @@ marketPlaceListNft = do guard $ valueOf out.amount curr name == one metadata <- MaybeT $ map hush $ getFullSeabugMetadataWithBackoff (curr /\ name) projectId + -- TODO: this is a temporary solution to only show NFTs known + -- to work. This filter catches a couple new nfts whose price + -- I put too low. The old nfts are caught above because their + -- metadata won't be parsed. + guard $ (unwrap metadata.seabugMetadata # _.ownerPrice) >= + (Natural.fromBigInt' minAdaOnlyUTxOValue) pure { input, output, metadata } pure $ catMaybes withMetadata diff --git a/src/Seabug/Contract/Mint.purs b/src/Seabug/Contract/Mint.purs new file mode 100644 index 0000000..d7bb443 --- /dev/null +++ b/src/Seabug/Contract/Mint.purs @@ -0,0 +1,122 @@ +module Seabug.Contract.Mint where + +import Contract.Prelude + +import Contract.Address + ( Slot + , getNetworkId + , ownPaymentPubKeyHash + , ownStakePubKeyHash + , payPubKeyHashBaseAddress + ) +import Contract.Chain (ChainTip(..), Tip(..), getTip) +import Contract.Monad (Contract, liftContractE, liftContractM, liftedE, liftedM) +import Contract.PlutusData (toData) +import Contract.ScriptLookups as Lookups +import Contract.Scripts (validatorHash) +import Contract.Time (from, getEraSummaries, getSystemStart, slotToPosixTime) +import Contract.Transaction (TransactionHash, balanceAndSignTxE, submit) +import Contract.TxConstraints as Constraints +import Contract.Utxos (utxosAt) +import Contract.Value + ( CurrencySymbol + , TokenName + , scriptCurrencySymbol + , singleton + ) +import Seabug.Contract.Util (setSeabugMetadata) +import Seabug.Lock (mkLockScript) +import Seabug.MarketPlace (marketplaceValidator) +import Seabug.MintingPolicy as MintingPolicy +import Seabug.Types + ( LockDatum(..) + , MarketplaceDatum(..) + , MintAct(..) + , MintParams(..) + , NftCollection(..) + , NftData(..) + , NftId(..) + ) +import Types.BigNum as BigNum + +-- | TODO: Is slot 0 for TipAtGenesis okay? +slotFromTip :: Tip -> Slot +slotFromTip TipAtGenesis = wrap $ BigNum.zero +slotFromTip (Tip (ChainTip { slot })) = slot + +-- | Mint the self-governed NFT for the given collection. +mintWithCollection + :: forall (r :: Row Type) + . CurrencySymbol /\ TokenName + -> MintParams + -> Contract r TransactionHash +mintWithCollection + (collectionNftCs /\ collectionNftTn) + ( MintParams + { price, lockLockup, lockLockupEnd, authorShare, daoShare } + ) = do + owner <- liftedM "Cannot get PaymentPubKeyHash" ownPaymentPubKeyHash + ownerStake <- liftedM "Cannot get StakePubKeyHash" ownStakePubKeyHash + networkId <- getNetworkId + addr <- liftContractM "Cannot get user address" $ + payPubKeyHashBaseAddress networkId owner ownerStake + utxos <- liftedM "Cannot get user utxos" $ utxosAt addr + currentSlot <- slotFromTip <$> getTip + marketplaceValidator' <- unwrap <$> liftContractE marketplaceValidator + lockingScript <- liftedE $ mkLockScript collectionNftCs lockLockup + lockLockupEnd + lockingScriptHash <- liftedM "Could not get locking script hash" $ liftAff $ + validatorHash lockingScript + let + nft = NftId { collectionNftTn, price, owner } + collection = NftCollection + { collectionNftCs + , lockLockup + , lockLockupEnd + , lockingScript: lockingScriptHash + , author: owner + , authorShare + , daoScript: marketplaceValidator'.validatorHash + , daoShare + } + policy <- liftedE $ MintingPolicy.mkMintingPolicy collection + curr <- liftedM "Could not get currency symbol" $ liftAff $ + scriptCurrencySymbol policy + tn <- liftedM "Could not get token name" $ MintingPolicy.mkTokenName nft + eraSummaries <- getEraSummaries + systemStart <- getSystemStart + now <- liftedE $ liftAff $ liftEffect $ + slotToPosixTime eraSummaries systemStart currentSlot + let + nftValue = singleton curr tn one + lookups = mconcat + [ Lookups.mintingPolicy policy, Lookups.unspentOutputs (unwrap utxos) ] + + constraints :: Constraints.TxConstraints Unit Unit + constraints = mconcat + [ Constraints.mustMintValueWithRedeemer (wrap $ toData $ MintToken nft) + nftValue + , Constraints.mustPayToScript marketplaceValidator'.validatorHash + ( wrap $ toData $ MarketplaceDatum $ + { getMarketplaceDatum: curr /\ tn } + ) + nftValue + , Constraints.mustPayToScript lockingScriptHash + ( wrap $ toData $ LockDatum + { sgNft: curr + , entered: currentSlot + , underlyingTn: collectionNftTn + } + ) $ singleton collectionNftCs collectionNftTn one + , Constraints.mustValidateIn $ from now + ] + unbalancedTx <- liftedE $ Lookups.mkUnbalancedTx lookups constraints + unbalancedTxWithMetadata <- setSeabugMetadata + (NftData { nftId: nft, nftCollection: collection }) + curr + unbalancedTx + signedTx <- liftedE $ balanceAndSignTxE unbalancedTxWithMetadata + transactionHash <- submit signedTx + log $ "Mint transaction successfully submitted with hash: " <> show + transactionHash + pure transactionHash diff --git a/src/Seabug/Contract/Util.purs b/src/Seabug/Contract/Util.purs new file mode 100644 index 0000000..e717ad6 --- /dev/null +++ b/src/Seabug/Contract/Util.purs @@ -0,0 +1,52 @@ +module Seabug.Contract.Util + ( minAdaOnlyUTxOValue + , setSeabugMetadata + ) where + +import Contract.Prelude + +import Contract.AuxiliaryData (setTxMetadata) +import Contract.Monad (Contract, liftContractM) +import Contract.Numeric.Natural (toBigInt) +import Contract.ScriptLookups (UnattachedUnbalancedTx) +import Contract.Value (CurrencySymbol) +import Contract.Value as Value +import Data.BigInt (BigInt) +import Data.BigInt as BigInt +import Seabug.Metadata.Share (mkShare) +import Seabug.Metadata.Types (SeabugMetadata(..)) +import Seabug.Types (NftData(..)) + +minAdaOnlyUTxOValue :: BigInt +minAdaOnlyUTxOValue = BigInt.fromInt 1_000_000 + +-- | Set metadata on the transaction for the given NFT +setSeabugMetadata + :: forall (r :: Row Type) + . NftData + -> CurrencySymbol -- | The currency symbol of the self-governed nft + -> UnattachedUnbalancedTx + -> Contract r UnattachedUnbalancedTx +setSeabugMetadata (NftData nftData) sgNftCurr tx = do + let + nftCollection = unwrap nftData.nftCollection + nftId = unwrap nftData.nftId + natToShare nat = liftContractM "Invalid share" + $ mkShare + =<< BigInt.toInt (toBigInt nat) + policyId = Value.currencyMPSHash sgNftCurr + authorShareValidated <- natToShare nftCollection.authorShare + marketplaceShareValidated <- natToShare nftCollection.daoShare + setTxMetadata tx $ SeabugMetadata + { policyId + , mintPolicy: mempty + , collectionNftCS: nftCollection.collectionNftCs + , lockingScript: nftCollection.lockingScript + , collectionNftTN: nftId.collectionNftTn + , authorPkh: unwrap nftCollection.author + , authorShare: authorShareValidated + , marketplaceScript: nftCollection.daoScript + , marketplaceShare: marketplaceShareValidated + , ownerPkh: unwrap nftId.owner + , ownerPrice: nftId.price + } diff --git a/src/Seabug/Lock.js b/src/Seabug/Lock.js new file mode 100644 index 0000000..b79fde2 --- /dev/null +++ b/src/Seabug/Lock.js @@ -0,0 +1,6 @@ +exports._unappliedLockScript = { + validator: { + getValidator: + "590d0f01000032333222323322323233223332223232332233322232323332223322332232323233223332223332223333322222323322332233223322323233332222332233223322332232323322323232333322223232222333222232223232323232323353049008225335306153353061533535057300b353022500722222222220072106310631063133573892010e43616e6e6f74206d696e742073670006215335306153353061332233355302f1200135048504723535503500122333553032120013504b504a23535503800122333535501d00123304d4800000488cc1380080048cc13400520000013355301c12001235355035001223355038002333535501a0012335530201200123535503900122335503c0023550210010012233355501b0640020012335530201200123535503900122335503c00235501f00100133355501605f00200135303035302e5335350573530200092235302400222222222223303800a00b21001132635305a335738921114f776e20696e707574206d697373696e670005b01f2200122200235303050082220021063133573892011a56616c75657320696e20434f2063616e6e6f74206368616e676500062153353061533530613322353024002222222222253353506333355303912001504225335306e333573466e3c0300041c01bc4d41980045419400c841c041b9401c008418c4cd5ce24811f4f776e6572206d757374207369676e20746865207472616e73616374696f6e000621533530615335306133355302d1200135019501b2333573466e1cccc050d4c0c4004888008d4c17c03488800cc13cccc154d4c17c03488800400800d2002064063353022500722222222220091063133573892119496e70757420646f6573206e6f7420636f6e7461696e20736700062153353061333573466e20d4c17803088800803418c18854cd4c1854cd4c1854010418c4cd5ce2492343757272656e7420736c6f7420736d616c6c6572207468616e206c6f636b7570456e64000621533530613305c35305e00c22233306200301000150061063133573892112496e636f6e73697374656e7420646174756d000621062153353061533530615003106313357389212843757272656e7420736c6f7420736d616c6c6572207468616e206c6f636b75702b656e7465726564000621533530613305c35305e00c222333062003337006a60c201e444004022002a00c20c6266ae7124112496e636f6e73697374656e7420646174756d0006210621062106210621062225335306153353061333355302d1200133504822230033002001200122064301e00906310631335738920112434f206d757374206e6f74206578697374730006215335306153353061333573466e1cccc04cd4c089401c888888888801cd4c17803088800cc138ccc150d4c17803088800400400920010630621063133573892011473674e4654206d757374206265206275726e656400062153353061333573466e20d4c17803088800803418c18854cd4c1854010418c4cd5ce2492343757272656e7420736c6f7420736d616c6c6572207468616e206c6f636b7570456e64000621533530615003106313357389212843757272656e7420736c6f7420736d616c6c6572207468616e206c6f636b75702b656e746572656400062106210621333573466e254008cdc00059a982d80491100102f8300999ab9a33712a0020120bc0be266e0ccdc09a9a8109a9a80f9a980ea801111111111100211001112999a9a8128011080089931a982b99ab9c49012456616c69642072616e676520626567696e6e696e67206d7573742062652066696e6974650005801c132635305733573892012456616c69642072616e676520626567696e6e696e67206d7573742062652066696e6974650005801c483c2032323cd7120d00f153353505132323232323333333574800a46666ae68cdc39aab9d5005480008cccd55cfa8029282d11999aab9f50052505b233335573ea00a4a0b846666aae7cd5d128031299a9a82e182d9aba150092153353505d32333333357480024a0c04a0c04a0c046a0c26eb400894180188d5d0a80490a99a9a82f182e9aba1500921350613330670030020011505f1505e1505d2505d05f05e05d05c2505901f2505825058250582505805a135744a00226ae8940044d55cf280089baa001533535051332235301e001222222222253353505d33355303312001503c235355039001225335306a333573466e3c00803c1b01ac4d418800c5418400884d4180d4d540e400488004541794cd4d4144d4c0a94008888004840044c98d4c150cd5ce249194d697373696e67206f757470757420646174756d2068617368000550195001210011326353054335738921144d697373696e67206f757470757420646174756d0005501921001132635305433573892117496e76616c696420434f20646174756d20666f726d6174000550191353019002220021533535048301600113263530523357389201054e6f20434f0005301722153353504a0011002221326353056335738921104d6f7265207468616e206f6e6520434f0005701b32001355059225335350470011504f2213535502b002225335305c3305800235305900722200313505400113006003375c0066eb4008dd680091119191800802990009aa82a9119a9a821800a4000446a6aa04e00444a66a60b0666ae68cdc780100482d02c8980380089803001990009aa82a1119a9a821000a4000446a6aa04c00444a66a60ae666ae68cdc780100382c82c080089803001888911199aa981f09000a82019aa98048900091a9aa8110009119aa8128011aa805000999aa981f09000911a9aa81180111299a982a199aa9810090009a806280711a9aa81300091198050010028030801899a822002001a82080099aa98048900091a9aa811000911919aa8130019800802990009aa82b11299a9a82200089aa8050019109a9aa81400111299a982c99806001004099aa80780380089803001801089091118018020891091119801002802089091118008020890008919a81811199a9a803001910010010009a9a80200091000990009aa825110891299a9a81d0008a81e11099a81e980200119aa980309000802000899a80111299a98240010825080082389109198008018010900091a9801800911a98038011111111111299a9a8231980d805005909a980f000911a9811000911199aa982209000911a98138011111a9817004111a98180029119299a983019a981f002919a981f8021299a9831199ab9a3371e0040020c80c62a00620c640c6466a607e00840c64a66a60c4666ae68cdc78010008320318a8018831899a82800500488048a99a9a82a80190a99a9a82b0011099a981e001119a981e801119a9820801119a98210011198308010009033119a9821001103311983080100091103311119a981f8021033111299a9833999ab9a3370e00c0060d20d02a66a60ce666ae68cdc38028010348340998250020008834083408308a99a9a82a800908308830a82380789931a982499ab9c491024c660004a00e4988848cc00400c0088004888888888848cccccccccc00402c02802402001c01801401000c008800448848cc00400c0084800448848cc00400c00848004484888c00c01044888008448880044800488cccd4c034004940bc940bc940bc8ccd54c0104800540348d4c018004894cd4c0ed4cd4c0ecccd5cd19b8f35301c0022200235301c0042200203d03c1333573466e1cd4c07000888004d4c070010880040f40f040f04d40cc00c540c800cc8004d540dc88448894cd4d40a00044d4d407c00c88004884ccd4d408401488008c010008ccd54c01c480040140100048848cc00400c008800488848ccc00401000c0088004448848cc00400c0084480048848cc00400c00880044cd4048894cd4d408c0088400c40054088848888c010014848888c00c014848888c008014848888c00401480048488c00800c888488ccc00401401000c80048488c00800c8488c00400c80048848cc00400c008800488ccd5cd19b870020010210201335005225335301e0021001101f01e12335003223335350060032200200200135350040012200112212330010030021200112212330010030021200122122330020040032212233001004003200123728666aa600424002e28020cc88cc008c8dca1980b0008059a9804001911001198011b943530080032220013300237286a6010006444006002a008a00a640026aa02a4422444a66a6a00c00220044426600a004666aa600e2400200a00800222440042442446600200800624002444246660020080060044002911002333333357480024a0084a0084a0084a00846a00a6eb800801848488c00800c44880044800448004800488d4c010008888d4c01c0108894cd4c034ccd5cd19b8f00600300f00e15335300d333573466e1c01400803c0384cc0240100044038403888ccd5cd19b8f0020010080072221233300100400300220013200135500422253353004333573466e2000920800400600513371600400226600666e0c0092080043371666e180092080040011220021220012001112323001001223300330020020011" + } +} diff --git a/src/Seabug/Lock.purs b/src/Seabug/Lock.purs new file mode 100644 index 0000000..316b3cf --- /dev/null +++ b/src/Seabug/Lock.purs @@ -0,0 +1,28 @@ +module Seabug.Lock where + +import Contract.Prelude + +import Contract.Address (Slot) +import Contract.Monad (Contract, liftContractE) +import Contract.PlutusData (toData) +import Contract.Scripts (Validator, applyArgs) +import Contract.Value (CurrencySymbol) +import Data.Argonaut (Json, JsonDecodeError) +import Data.BigInt (BigInt) +import QueryM as QueryM +import Seabug.Helpers (jsonReader) + +mkLockScript + :: forall (r :: Row Type) + . CurrencySymbol + -> BigInt + -> Slot + -> Contract r (Either QueryM.ClientError Validator) +mkLockScript collectionNftCs lockup lockupEnd = do + script <- liftContractE unappliedLockScript + applyArgs script [ toData collectionNftCs, toData lockup, toData lockupEnd ] + +unappliedLockScript :: Either JsonDecodeError Validator +unappliedLockScript = jsonReader "validator" _unappliedLockScript + +foreign import _unappliedLockScript :: Json diff --git a/src/Seabug/Metadata.purs b/src/Seabug/Metadata.purs index 36ed4a4..74fcefa 100644 --- a/src/Seabug/Metadata.purs +++ b/src/Seabug/Metadata.purs @@ -13,14 +13,12 @@ import Affjax (printError) import Affjax as Affjax import Affjax.RequestHeader as Affjax.RequestHeader import Affjax.ResponseFormat as Affjax.ResponseFormat -import Cardano.Types.Value as Cardano.Types.Value -import Contract.Prim.ByteArray (byteArrayToHex) +import Contract.Prim.ByteArray (ByteArray, byteArrayToHex) import Contract.Value ( CurrencySymbol , TokenName , getCurrencySymbol , getTokenName - , mkCurrencySymbol ) import Control.Alternative (guard) import Control.Monad.Error.Class (throwError) @@ -29,6 +27,7 @@ import Control.Monad.Reader (ReaderT, runReaderT) import Control.Monad.Reader.Trans (asks) import Control.Monad.Trans.Class (lift) import Data.Argonaut as Argonaut +import Data.Array (head) import Data.Bifunctor (lmap) import Data.Function (on) import Data.HTTP.Method (Method(GET)) @@ -36,7 +35,6 @@ import Data.Newtype (unwrap) import Effect.Aff (delay) import Effect.Random (randomRange) import Seabug.Metadata.Types (SeabugMetadata(SeabugMetadata)) -import Partial.Unsafe (unsafePartial) type Hash = String @@ -95,16 +93,28 @@ getFullSeabugMetadata a@(currSym /\ _) projectId = ipfsHash <- getIpfsHash seabugMetadata pure { seabugMetadata, ipfsHash } +-- | Convert a byte array into a string as represented in the metadata +-- | json, i.e. hex encoded with "0x" prepended. +metadataBytesString :: ByteArray -> String +metadataBytesString = ("0x" <> _) <<< byteArrayToHex + getIpfsHash :: SeabugMetadata -> BlockfrostFetch Hash getIpfsHash (SeabugMetadata { collectionNftCS, collectionNftTN }) = do - except <<< (decodeField "image" <=< decodeField "onchain_metadata") - =<< mkGetRequest ("assets/" <> mkAsset curr collectionNftTN) + r <- mkGetRequest ("assets/" <> mkAsset collectionNftCS collectionNftTN) + imageArray <- except $ + ( decodeField "image" <=< decodeField tokenNameKey + <=< decodeField currSymKey + <=< decodeField "onchain_metadata" + ) r + except $ note (BlockfrostOtherError "Empty image array") $ head imageArray where - curr :: CurrencySymbol - curr = unsafePartial $ fromJust $ mkCurrencySymbol $ - Cardano.Types.Value.getCurrencySymbol collectionNftCS + currSymKey :: String + currSymKey = metadataBytesString $ getCurrencySymbol collectionNftCS + + tokenNameKey :: String + tokenNameKey = metadataBytesString $ getTokenName collectionNftTN getMintingTxSeabugMetadata :: forall (r :: Row Type) @@ -132,7 +142,7 @@ getMintingTxSeabugMetadata currSym txHash = do Aeson.decodeAeson =<< Aeson.getField md currSymKey currSymKey :: String - currSymKey = byteArrayToHex $ getCurrencySymbol currSym + currSymKey = metadataBytesString $ getCurrencySymbol currSym getMintingTxHash :: forall (r :: Row Type) diff --git a/src/Seabug/Metadata/Types.purs b/src/Seabug/Metadata/Types.purs index 6cc5f34..02fc15a 100644 --- a/src/Seabug/Metadata/Types.purs +++ b/src/Seabug/Metadata/Types.purs @@ -5,15 +5,8 @@ module Seabug.Metadata.Types import Prelude -import Aeson - ( class DecodeAeson - , JsonDecodeError - ( TypeMismatch - ) - , caseAesonObject - , decodeAeson - , getField - ) +import Aeson (class DecodeAeson, JsonDecodeError(..), caseAesonObject, getField) +import Contract.Value (CurrencySymbol, mkCurrencySymbol) import Data.BigInt (fromInt) as BigInt import Data.Either (Either(Left), note) import Data.Generic.Rep (class Generic) @@ -21,26 +14,30 @@ import Data.Map (toUnfoldable) as Map import Data.Maybe (Maybe(Nothing), fromJust) import Data.Newtype (class Newtype, wrap) import Data.Show.Generic (genericShow) +import Data.String (Pattern(..), stripPrefix) import Data.Tuple (Tuple(Tuple)) import Data.Tuple.Nested ((/\)) import FromData (class FromData, fromData) -import Metadata.Helpers (unsafeMkKey, lookupKey, lookupMetadata) -import Seabug.Metadata.Share (Share, mkShare) import Metadata.FromMetadata (class FromMetadata, fromMetadata) +import Metadata.Helpers (unsafeMkKey, lookupKey, lookupMetadata) import Metadata.MetadataType (class MetadataType, metadataLabel) import Metadata.ToMetadata (class ToMetadata, toMetadata) import Partial.Unsafe (unsafePartial) import Plutus.Types.AssocMap (Map(Map)) as AssocMap +import Seabug.Metadata.Share (Share, mkShare) +import Serialization.Hash + ( ScriptHash + , ed25519KeyHashFromBytes + , scriptHashFromBytes + ) import ToData (class ToData, toData) -import Serialization.Hash (ScriptHash, scriptHashFromBytes) import Type.Proxy (Proxy(Proxy)) import Types.ByteArray (ByteArray, hexToByteArray) -import Types.RawBytes (hexToRawBytesUnsafe) import Types.Natural (Natural) import Types.PlutusData (PlutusData(Map)) import Types.PubKeyHash (PubKeyHash) +import Types.RawBytes (hexToRawBytes, hexToRawBytesUnsafe) import Types.Scripts (MintingPolicyHash, ValidatorHash) -import Cardano.Types.Value (CurrencySymbol, mkCurrencySymbol) import Types.TokenName (TokenName, mkTokenName) import Types.TransactionMetadata (TransactionMetadatum(MetadataMap)) @@ -180,24 +177,24 @@ instance DecodeAeson SeabugMetadata where $ \o -> do collectionNftCS <- note (TypeMismatch "Invalid ByteArray") - <<< (mkCurrencySymbol <=< hexToByteArray) + <<< + ( mkCurrencySymbol <=< hexToByteArray <=< + removeMetadataBytesPrefix + ) =<< getField o "collectionNftCS" collectionNftTN <- note (TypeMismatch "expected ASCII-encoded `TokenName`") - <<< (mkTokenName <=< hexToByteArray) + <<< (mkTokenName <=< hexToByteArray <=< removeMetadataBytesPrefix) =<< getField o "collectionNftTN" lockingScript <- map wrap <<< decodeScriptHash =<< getField o "lockingScript" - authorPkh <- - map wrap - <<< decodeAeson =<< getField o "authorPkh" + authorPkh <- decodePkh =<< getField o "authorPkh" authorShare <- decodeShare =<< getField o "authorShare" marketplaceScript <- map wrap <<< decodeScriptHash =<< getField o "marketplaceScript" marketplaceShare <- decodeShare =<< getField o "marketplaceShare" - ownerPkh <- map wrap <<< decodeAeson =<< getField o - "ownerPkh" + ownerPkh <- decodePkh =<< getField o "ownerPkh" ownerPrice <- getField o "ownerPrice" pure $ SeabugMetadata { -- Not used in the endpoints where we parse the metadata, so we @@ -220,6 +217,16 @@ instance DecodeAeson SeabugMetadata where , ownerPrice } where + decodePkh :: String -> Either JsonDecodeError PubKeyHash + decodePkh = + map wrap <<< + ( note (TypeMismatch "Invalid Ed25519KeyHash") <<< + ed25519KeyHashFromBytes + <=< note (TypeMismatch "Invalid ByteArray") <<< + hexToRawBytes + ) <=< note (TypeMismatch "Expected 0x prefix in authorPkh") + <<< removeMetadataBytesPrefix + decodeShare :: Int -> Either JsonDecodeError Share decodeShare = note (TypeMismatch "Expected int between 0 and 10000") <<< mkShare @@ -228,7 +235,13 @@ instance DecodeAeson SeabugMetadata where decodeScriptHash = note (TypeMismatch "Expected hex-encoded script hash") - <<< (scriptHashFromBytes <<< wrap <=< hexToByteArray) + <<< + ( scriptHashFromBytes <<< wrap <=< hexToByteArray <=< + removeMetadataBytesPrefix + ) + + removeMetadataBytesPrefix :: String -> Maybe String + removeMetadataBytesPrefix = stripPrefix (Pattern "0x") newtype SeabugMetadataDelta = SeabugMetadataDelta { policyId :: MintingPolicyHash diff --git a/src/Seabug/MintingPolicy.purs b/src/Seabug/MintingPolicy.purs index c641ce6..4fc4216 100644 --- a/src/Seabug/MintingPolicy.purs +++ b/src/Seabug/MintingPolicy.purs @@ -1,13 +1,49 @@ module Seabug.MintingPolicy - ( mintingPolicy + ( mkMintingPolicy + , mkTokenName + , unappliedMintingPolicy ) where import Contract.Prelude -import Contract.Scripts (MintingPolicy) + +import Contract.Monad (Contract, liftContractE) +import Contract.PlutusData (toData) +import Contract.Scripts (MintingPolicy, applyArgs) +import Contract.Value (TokenName) +import Contract.Value as Value import Data.Argonaut (Json, JsonDecodeError) +import QueryM as QueryM import Seabug.Helpers (jsonReader) +import Seabug.Types (NftCollection(..), NftId, hash) + +mkTokenName :: forall (r :: Row Type). NftId -> Contract r (Maybe TokenName) +mkTokenName nftId = hash nftId <#> maybe Nothing Value.mkTokenName + +mkMintingPolicy + :: forall (r :: Row Type) + . NftCollection + -> Contract r (Either QueryM.ClientError MintingPolicy) +mkMintingPolicy + ( NftCollection + { collectionNftCs + , lockingScript + , author + , authorShare + , daoScript + , daoShare + } + ) = do + p <- liftContractE unappliedMintingPolicy + applyArgs p + [ toData collectionNftCs + , toData lockingScript + , toData author + , toData authorShare + , toData daoScript + , toData daoShare + ] -mintingPolicy :: Either JsonDecodeError MintingPolicy -mintingPolicy = jsonReader "mintingPolicy" _mintingPolicy +unappliedMintingPolicy :: Either JsonDecodeError MintingPolicy +unappliedMintingPolicy = jsonReader "mintingPolicy" _mintingPolicy foreign import _mintingPolicy :: Json diff --git a/src/Seabug/Seabug.purs b/src/Seabug/Seabug.purs index 6edb6c6..6b3b2f7 100644 --- a/src/Seabug/Seabug.purs +++ b/src/Seabug/Seabug.purs @@ -1,12 +1,41 @@ module Seabug ( module Seabug.CallContract , module QueryM.Utxos + , mint ) where +import Contract.Prelude + +import Control.Promise (Promise) +import Data.BigInt as BigInt +import QueryM.Utxos (getWalletBalance) import Seabug.CallContract ( callMarketPlaceBuy , callMarketPlaceBuyTest , callMarketPlaceListNft , callMarketPlaceFetchNft + , callMint ) -import QueryM.Utxos (getWalletBalance) + +mint :: Effect (Promise Unit) +mint = callMint + { serverHost: "ctl.localho.st" + , serverPort: 8080 + , serverSecureConn: false + , ogmiosHost: "localho.st" + , ogmiosPort: 1337 + , ogmiosSecureConn: false + , datumCacheHost: "localho.st" + , datumCachePort: 9999 + , datumCacheSecureConn: false + , networkId: 0 + , projectId: "testnetu7qDM8q2XT1S6gEBSicUIqXB6QN60l7B" + , logLevel: "Trace" + } + { -- base36 ipfs cid obtained from mint-nft.sh + imageUri: "ipfs://k2cwuebwvb6kdiwob6sb2yqnz38r0yv72q1xijbts9ep5lq3nm8rw3i4" + , tokenNameString: "abcdef" + , name: "Piaggio Ape" + , description: "Seabug Testing" + , price: BigInt.fromInt (12 * 1000000) + } diff --git a/src/Seabug/Token.js b/src/Seabug/Token.js deleted file mode 100644 index a3482eb..0000000 --- a/src/Seabug/Token.js +++ /dev/null @@ -1,4 +0,0 @@ -exports._unappliedMintingPolicy = { - mintingPolicy: - "590a9a010000323332223232323232332232332232323332223332223332223322323332223232332232323322323333322222332233333222223322332233223232323232222222223235300f0022235301300222223222222233335302901023232323232300100e3200135505a2253353503e0011533530593335303d12001051500332635302e3357389210b756e726561636861626c650002f01f150051500422135355054002225335305d333573466e3c009406417c17854cd4c174ccd4c10448004155401c00454024540204c01800c4cd40f0cd54140c0d4010cdc0a40009001281e8a99a982a99ab9c4901124e4654206d757374206265206275726e6564000561500110561533530543301b00f3530350022220011500115335305433573892011f4f776e6572206d757374207369676e20746865207472616e73616374696f6e0005515001105515335305333355301c120013502f50482353022001222533530573303f00333041304901a504310581333573466e1cccc07000806cd4c0e001488800d200205905800b105513357389211f556e6465726c79696e67204e4654206d75737420626520756e6c6f636b656400054232323232323225335305a33300f00835303b0082220020011500215335305a33573892013e45786163746c79206f6e65206e657720746f6b656e206d757374206265206d696e74656420616e642065786163746c79206f6e65206f6c64206275726e740005b15002105b15335305833004500233042304a018504415335305833004500133042304b01a50441533530583335530211200135034504d3300533042304b35303900622200150443370266e05400cc1514004c151400804041685415854158541584cdc199b8250020184828270044cdc199b8250010154828270044d4c0d800c888008894cd4c158ccd5cd19b880020530580571058133355301f1200135032504b3300300100200e2223530240012225335305933041006003153353059333573466e1c014ccc0780080e40e416c16854cd4d4110004854cd4d4114d4c09805488888888894cd4d413cccd54c0b44800540b08d4d54178004894cd4c19cccd5cd19b8f00200e0690681350540031505300221350523535505e00122001150502132333573466ebc008004178174c8d4d5415400488cdd2a400066ae80dd480119aba037520026ec4090cd54155405cc0e8024416c4168416841688c894cd4c154ccc02800c004d4c0d800c8880045400854cd4c154cd5ce2493e45786163746c79206f6e65206e657720746f6b656e206d757374206265206d696e74656420616e642065786163746c79206f6e65206f6c64206275726e74000561500210561533530533301a00e353034001222001105513357389211f4f776e6572206d757374207369676e20746865207472616e73616374696f6e00054232323232300100d320013550592253353503d001153353503d32635302d3357389210b756e726561636861626c650002e01e150042213300500200122135355053002225335305c333573466e3c009406017817454cd4d410400454020884cc0240080044c01800c88d4d54140008894cd4d40f800c54cd4c164ccd5cd19b8f002303800705b05a153353059333573466e1c005200205b05a150061500515005221500715335305433573892011e45786163746c79206f6e65204e4654206d757374206265206d696e7465640005515001105515335305333355301c120013502f50482353022001222533530573303f00333041304901a50431333573466e1cccc07000806cd4c0e001488800d2002059058105800b105513357389211d556e6465726c79696e67204e4654206d757374206265206c6f636b6564000542322232323001007320013550532253353503700110532213535504d0022253353056333573466e3c009404816015c54cd4d40ec004415c884d4d54144008894cd4d40fc00c416c884d4d5415400888c94cd4d411001054cd4c17cccd5cd19b8f007501306106015335305f333573466e3c00d404018418054cd4c17cccd5cd19b87006480041841804ccd5cd19b87002480081841804180540045400488418854cd4c178ccd5cd19b8f002501206005f15335305e333573466e3c019403c18017c54cd4c178ccd5cd19b870014800418017c4ccd5cd19b870054800818017c417c417c417c4c01800c4c0b8d4c0c0010888ccc0d000c0140104c0ac0044d4c03800488cccd4c0580048c98d4c070cd5ce249024c680001d00d2001232635301c3357389201024c680001d00d232635301c3357389201024c680001d00d222323230010053200135504222335350260014800088d4d540f0008894cd4c114ccd5cd19b8f00200904704613007001130060033200135504122335350250014800088d4d540ec008894cd4c110ccd5cd19b8f00200704604510011300600349888d4c01c00888888888894cd4d40c0ccd54c03848005403494cd4c118ccd5cd19b8f00c0010480471350330011503200321048104613350162253353502500221003100150243200135503a2211222533535021001135350190032200122133353501b005220023004002333553007120010050040012212330010030022001222222222212333333333300100b00a009008007006005004003002200122212333001004003002200121222230040052122223003005212222300200521222230010052001120012001212222300400522122223300300600522122223300200600521222230010052001123350032233353501d00322002002001353501b0012200112212330010030021200123724666aa600a24002e28008cc88cc008c8dc9198120008029a9802801911001198011b923530050032220013300237246a600a006444006002a010a01291100222123330010040030022001320013550202211222533535007001100222133005002333553007120010050040013200135501f22122253353500600215335350060011023221024221533535008003102422153353025330070040021333530091200100700300110261122002122122330010040031200122353003002223530050032232335301000523353011004253353021333573466e3c00800408c0885400c408880888cd4c044010808894cd4c084ccd5cd19b8f00200102302215003102215335350090032153353500a00221335300e0022335300f002233530130022335301400223301800200120252335301400220252330180020012220252223353011004202522253353026333573466e1c01800c0a009c54cd4c098ccd5cd19b87005002028027133021004001102710271020153353500900121020102022123300100300220011212230020031122001120012122300200322212233300100500400320012122300200321223001003200122333573466e3c00800404003c4cd4008894cd4c034008403c400403048848cc00400c0084800488d4d5400c00888d4d5401400c894cd4c038ccd5cd19b8f00400201000f133009003001100f1122123300100300211200122333573466e1c00800402402094cd4c014ccd5cd19b880010020070061480004005208092f401133573892113526f79616c6974696573206e6f742070616964000033200135500422253353004333573466e2000920800400600513371600400226600666e0c0092080043371666e180092080040011220021220012001112323001001223300330020020011", -}; diff --git a/src/Seabug/Token.purs b/src/Seabug/Token.purs deleted file mode 100644 index f07aec2..0000000 --- a/src/Seabug/Token.purs +++ /dev/null @@ -1,58 +0,0 @@ -module Seabug.Token - ( mkTokenName - , policy - , unappliedMintingPolicy - ) where - -import Contract.Prelude -import Contract.Monad (Contract) -import Contract.PlutusData (toData) -import Contract.Scripts (MintingPolicy, applyArgsM) -import Contract.Value (mkTokenName) as Value -import Contract.Value (TokenName) -import Data.Argonaut (Json, JsonDecodeError) -import Seabug.Helpers (jsonReader) -import Seabug.Types (NftCollection(NftCollection), NftId, hash) - --- rev: 2c9ce295ccef4af3f3cb785982dfe554f8781541 -mkTokenName :: forall (r :: Row Type). NftId -> Contract r (Maybe TokenName) -mkTokenName nftId = hash nftId <#> maybe Nothing Value.mkTokenName - --- rev: 2c9ce295ccef4af3f3cb785982dfe554f8781541 --- Apply arguments to an unapplied `MintingPolicy` to give a `MintingPolicy`. --- It's possible this is given as JSON since we don't have --- `mkMintingPolicyScript`. -policy - :: forall (r :: Row Type) - . NftCollection - -> MintingPolicy - -> Contract r (Maybe MintingPolicy) -policy - ( NftCollection - { collectionNftCs -- CurrencySymbol - , lockingScript -- ValidatorHash - , author -- PaymentPubKeyHash - , authorShare -- Natural - , daoScript -- ValidatorHash - , daoShare -- Natural - } - ) - mph = - let - pd = - [ toData collectionNftCs - , toData lockingScript - , toData author - , toData authorShare - , toData daoScript - , toData daoShare - ] - in - applyArgsM mph pd - --- This is read in locally as a minting policy with unapplied arguments. We --- may prefer to change this to a fully appllied MintingPolicy. -unappliedMintingPolicy :: Either JsonDecodeError MintingPolicy -unappliedMintingPolicy = jsonReader "mintingPolicy" _unappliedMintingPolicy - -foreign import _unappliedMintingPolicy :: Json diff --git a/src/Seabug/Types.purs b/src/Seabug/Types.purs index bf2d02e..6795c6b 100644 --- a/src/Seabug/Types.purs +++ b/src/Seabug/Types.purs @@ -1,27 +1,22 @@ module Seabug.Types ( MarketplaceDatum(..) + , LockDatum(..) , MintAct(..) , MintParams(..) , NftCollection(..) , NftData(..) , NftId(..) + , MintCnftParams(..) , class Hashable , hash ) where import Contract.Prelude -import Cardano.Types.Value as Cardano.Types.Value -import Contract.Value - ( CurrencySymbol - , TokenName - , getCurrencySymbol - , getTokenName - , mkCurrencySymbol - ) -import Contract.Monad (Contract) import Contract.Address (PaymentPubKeyHash, PubKeyHash) import Contract.Aeson as Aeson +import Contract.Monad (Contract) +import Contract.Numeric.Natural (Natural, toBigInt) import Contract.PlutusData ( class FromData , class ToData @@ -29,19 +24,36 @@ import Contract.PlutusData , fromData , toData ) -import Contract.Prim.ByteArray - ( ByteArray - , byteArrayFromIntArrayUnsafe - ) -import Contract.Numeric.Natural (Natural, toBigInt) +import Contract.Prim.ByteArray (ByteArray, byteArrayFromIntArrayUnsafe) import Contract.Scripts (ValidatorHash) import Contract.Time (Slot) +import Contract.Value + ( CurrencySymbol + , TokenName + , getCurrencySymbol + , getTokenName + ) import Data.Argonaut as Json import Data.BigInt (BigInt, fromInt, toInt) import Hashing (blake2b256Hash) import Partial.Unsafe (unsafePartial) import Serialization.Hash (ed25519KeyHashToBytes, scriptHashToBytes) +newtype MintCnftParams = MintCnftParams + { imageUri :: String + -- | The token name of the collection nft. Will be base64 encoded + , tokenNameString :: String + , name :: String + , description :: String + } + +derive instance Generic MintCnftParams _ +derive instance Newtype MintCnftParams _ +derive newtype instance Eq MintCnftParams + +instance Show MintCnftParams where + show = genericShow + -- Field names have been simplified due to row polymorphism. Please let me know -- if the field names must be exact. -- | Parameters that need to be submitted when minting a new NFT. @@ -53,8 +65,7 @@ newtype MintParams = MintParams price :: Natural , lockLockup :: BigInt , lockLockupEnd :: Slot - , fakeAuthor :: Maybe PaymentPubKeyHash - , feeVaultKeys :: Array PubKeyHash -- `List` is also an option + , feeVaultKeys :: Array PubKeyHash } derive instance Generic MintParams _ @@ -65,14 +76,13 @@ instance Show MintParams where show = genericShow instance FromData MintParams where - fromData (Constr n [ as, ds, pr, ll, lle, fa, fvk ]) | n == zero = + fromData (Constr n [ as, ds, pr, ll, lle, fvk ]) | n == zero = MintParams <$> ( { authorShare: _ , daoShare: _ , price: _ , lockLockup: _ , lockLockupEnd: _ - , fakeAuthor: _ , feeVaultKeys: _ } <$> fromData as @@ -80,7 +90,6 @@ instance FromData MintParams where <*> fromData pr <*> fromData ll <*> fromData lle - <*> fromData fa <*> fromData fvk ) fromData _ = Nothing @@ -93,7 +102,6 @@ instance ToData MintParams where , price , lockLockup , lockLockupEnd - , fakeAuthor , feeVaultKeys } ) = @@ -103,7 +111,6 @@ instance ToData MintParams where , toData price , toData lockLockup , toData lockLockupEnd - , toData fakeAuthor , toData feeVaultKeys ] @@ -161,12 +168,7 @@ instance Aeson.DecodeAeson NftCollection where (Left $ Json.TypeMismatch "Expected Json Object") ( \o -> do - collectionNftCs <- do - nftCs <- Aeson.getField o "nftCollection'collectionNftCs" - note (Json.TypeMismatch "expected currency symbol") - $ mkCurrencySymbol - $ Cardano.Types.Value.getCurrencySymbol nftCs - + collectionNftCs <- Aeson.getField o "nftCollection'collectionNftCs" lockLockupEnd <- Aeson.getField o "nftCollection'lockLockupEnd" lockingScript <- Aeson.getField o "nftCollection'lockingScript" author <- Aeson.getField o "nftCollection'author" diff --git a/test/Fixtures.purs b/test/Fixtures.purs index c849110..0719dbc 100644 --- a/test/Fixtures.purs +++ b/test/Fixtures.purs @@ -21,14 +21,13 @@ import Contract.Numeric.Natural as Natural import Contract.Prelude (fromJust) import Contract.Prim.ByteArray (hexToByteArrayUnsafe) import Contract.Scripts (MintingPolicyHash(..), ScriptHash, ValidatorHash(..)) -import Contract.Value (TokenName, mkTokenName) +import Contract.Value (CurrencySymbol, mkCurrencySymbol, TokenName, mkTokenName) import Data.BigInt as BigInt -import Seabug.Metadata.Types (SeabugMetadata(..), SeabugMetadataDelta(..)) -import Seabug.Metadata.Share (Share, mkShare) import Partial.Unsafe (unsafePartial) +import Seabug.Metadata.Share (Share, mkShare) +import Seabug.Metadata.Types (SeabugMetadata(..), SeabugMetadataDelta(..)) import Serialization.Hash (ed25519KeyHashFromBytes, scriptHashFromBytes) import Types.RawBytes (hexToRawBytesUnsafe) -import Cardano.Types.Value (CurrencySymbol, mkCurrencySymbol) currencySymbol1 :: CurrencySymbol currencySymbol1 = unsafePartial $ fromJust $ mkCurrencySymbol $