āĻāĻĢāĻāĻŋāĻāĻŽ āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ āĻā§āĻ¸ā§āĻāĻ¨ā§āĻā§ āĻāĻāĻ-āĻā§āĻ¨āĻžāĻ°ā§āĻā§āĻĄ āĻāĻ°ā§āĻ āĻāĻ¨āĻāĻĢāĻāĻŋ āĻŽāĻŋāĻ¨ā§āĻ āĻāĻ°āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻĒāĻ¨āĻžāĻ° āĻ¨āĻŋāĻāĻ¸ā§āĻŦ āĻā§āĻā§āĻ¸āĻ-āĻā§ āĻāĻŽā§āĻ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻ āĻ¸āĻš āĻāĻāĻāĻŋ DApp āĻ¤ā§āĻ°āĻŋ, āĻāĻžāĻ˛āĻžāĻ¨ā§ āĻāĻŦāĻ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻ¸āĻŽā§āĻĒā§āĻ°ā§āĻŖ āĻ¨āĻŋāĻ°ā§āĻĻā§āĻļāĻŋāĻāĻž!
āĻāĻ āĻŦā§āĻ˛āĻāĻāĻŋ āĻāĻĒāĻ¨āĻžāĻā§ āĻā§āĻāĻžāĻŦā§ āĻ¤āĻž āĻ¨āĻŋāĻ¯āĻŧā§ āĻ¯ā§āĻ¤ā§ āĻšāĻŦā§
Tensorflow āĻāĻ° āĻāĻĒāĻ° āĻāĻŋāĻ¤ā§āĻ¤āĻŋ āĻāĻ°ā§ āĻāĻāĻāĻŋ āĻāĻĒā§āĻ¨āĻ¸ā§āĻ°ā§āĻ¸ āĻĒāĻžāĻāĻĨāĻ¨-āĻāĻŋāĻ¤ā§āĻ¤āĻŋāĻ āĻā§āĻā§āĻ¸āĻ-āĻā§-āĻāĻŽā§āĻ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻ āĻ¤ā§āĻ°āĻŋ āĻāĻ°ā§āĻ¨ (āĻāĻāĻŋ āĻāĻĒāĻ¨āĻžāĻ° āĻāĻā§āĻ°āĻšā§āĻ° āĻ¨āĻž āĻšāĻ˛ā§ āĻāĻĒāĻ¨āĻŋ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° Bacalhau HTTP āĻāĻ¨ā§āĻĄāĻĒāĻ¯āĻŧā§āĻ¨ā§āĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨)
Bacalhau-āĻ āĻāĻ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻāĻŋ āĻāĻžāĻ˛āĻžāĻ¨ (āĻāĻāĻāĻŋ āĻā§āĻ˛āĻž p2p āĻ āĻĢ-āĻā§āĻāĻ¨ āĻāĻŽā§āĻĒāĻŋāĻāĻ āĻĒā§āĻ˛ā§āĻ¯āĻžāĻāĻĢāĻ°ā§āĻŽ)
āĻ¸āĻ˛āĻŋāĻĄāĻŋāĻāĻŋāĻ¤ā§ āĻāĻāĻāĻŋ NFT āĻā§āĻā§āĻ¤āĻŋ āĻ¤ā§āĻ°āĻŋ āĻāĻ°ā§āĻ¨ (āĻāĻāĻāĻŋ āĻāĻĒā§āĻ¨ āĻā§āĻĒā§āĻ˛āĻŋāĻ¨ ERC721 āĻā§āĻā§āĻ¤āĻŋāĻ° āĻāĻĒāĻ° āĻāĻŋāĻ¤ā§āĻ¤āĻŋ āĻāĻ°ā§)
Filecoin āĻāĻžāĻ°ā§āĻā§āĻ¯āĻŧāĻžāĻ˛ āĻŽā§āĻļāĻŋāĻ¨ (FVM) āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ āĻā§āĻ¸ā§āĻāĻ¨ā§āĻā§ āĻšāĻžāĻ°ā§āĻĄāĻšāĻžāĻā§āĻ° āĻ¸āĻžāĻĨā§ NFT āĻā§āĻā§āĻ¤āĻŋ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°ā§āĻ¨
āĻĢā§āĻ°āĻ¨ā§āĻ-āĻāĻ¨ā§āĻĄ āĻāĻ¨ā§āĻāĻžāĻ°āĻ ā§āĻ¯āĻžāĻāĻļāĻ¨ - āĻŦāĻžāĻāĻžāĻ˛āĻšāĻžāĻ āĻā§āĻā§āĻ¸āĻ-āĻā§-āĻāĻŽā§āĻ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻ āĻāĻŦāĻ āĻĒā§āĻ°āĻ¤āĻŋāĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ¤ā§ āĻāĻĒāĻ¨āĻžāĻ° NFT āĻā§āĻā§āĻ¤āĻŋāĻ° āĻ¸āĻžāĻĨā§ āĻā§āĻāĻžāĻŦā§ āĻāĻ¨ā§āĻāĻžāĻ°āĻ ā§āĻ¯āĻžāĻā§āĻ āĻāĻ°āĻŦā§āĻ¨
āĻāĻŋāĻāĻžāĻŦā§ āĻāĻĒāĻ¨āĻžāĻ° NFT āĻŽā§āĻāĻžāĻĄā§āĻāĻž NFT.Storage āĻ āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°āĻŦā§āĻ¨
āĻā§āĻāĻžāĻŦā§ āĻāĻĒāĻ¨āĻžāĻ° āĻĢā§āĻ°āĻ¨ā§āĻ-āĻāĻ¨ā§āĻĄ āĻĄāĻŋāĻāĻĒāĻā§ āĻĢā§āĻ˛āĻŋāĻā§ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°āĻŦā§āĻ¨
āĻāĻŽāĻŋ āĻāĻā§āĻāĻžāĻā§āĻ¤āĻāĻžāĻŦā§ āĻāĻ āĻ¸ā§āĻā§āĻ¯āĻžāĻā§ āĻāĻĒāĻ˛āĻŦā§āĻ§ āĻ¯āĻ¤āĻāĻž āĻāĻĒā§āĻ¨ āĻ¸ā§āĻ°ā§āĻ¸ āĻāĻŦāĻ āĻŦāĻŋāĻā§āĻ¨ā§āĻĻā§āĻ°ā§āĻā§āĻ¤ āĻĒā§āĻ°āĻ¯ā§āĻā§āĻ¤āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻž āĻŦā§āĻā§ āĻ¨āĻŋāĻ¯āĻŧā§āĻāĻŋāĨ¤
āĻāĻ āĻŦā§āĻ˛āĻāĻāĻŋ āĻŦā§āĻļ āĻĻā§āĻ°ā§āĻ āĻšāĻ¤ā§ āĻāĻ˛ā§āĻā§ (āĻāĻ°ā§ - āĻāĻŽāĻŋ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ¤āĻĨā§āĻ¯ āĻĻāĻŋāĻ¤ā§ āĻāĻžāĻ āĻāĻŦāĻ āĻ¨āĻŋāĻļā§āĻāĻŋāĻ¤ āĻāĻ°āĻ¤ā§ āĻāĻžāĻ āĻ¯ā§ āĻāĻŽāĻ°āĻž āĻļāĻŋāĻā§āĻˇāĻžāĻ¨āĻŦāĻŋāĻ¸-āĻŦāĻžāĻ¨ā§āĻ§āĻŦ āĻāĻŦāĻ āĻ āĻ¨ā§āĻ¤āĻ°ā§āĻā§āĻā§āĻ¤ āĻāĻ°āĻāĻŋ!) - āĻ¤āĻžāĻ āĻā§āĻŦāĻŋāĻ˛ā§ āĻāĻĒāĻ¨āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻĒāĻ¯ā§āĻā§ āĻ āĻāĻļāĻā§āĻ˛āĻŋ āĻāĻĄāĻŧāĻŋāĻ¯āĻŧā§ āĻ¯ā§āĻ¤ā§ āĻĻā§āĻŦāĻŋāĻ§āĻž āĻŦā§āĻ§ āĻāĻ°ā§āĻ¨ āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ <3
(āĻāĻāĻŋ āĻĒāĻžāĻ¨ - āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻĒā§āĻ¯āĻžāĻ¨āĻā§āĻ āĻ¸ā§āĻā§āĻ¯āĻžāĻ #sorrynotsorry)
āĻāĻĒā§āĻ¨ āĻ¸ā§āĻ°ā§āĻ¸ āĻāĻŦāĻ āĻāĻ¯āĻŧā§āĻŦ3-āĻŽā§āĻ˛ā§āĻ¯ āĻĨā§āĻā§ :)
đĄ TLDR āĻāĻŋāĻĒ đĄ
āĻāĻ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻāĻŋ āĻāĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§āĻ CLI āĻāĻŦāĻ āĻāĻāĻāĻŋ HTTP āĻāĻ¨ā§āĻĄāĻĒāĻ¯āĻŧā§āĻ¨ā§āĻā§āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§ Bacalhau-āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻĒāĻ˛āĻŦā§āĻ§, āĻ¤āĻžāĻ āĻ¨āĻŋāĻ°ā§āĻĻā§āĻŦāĻŋāĻ§āĻžāĻ¯āĻŧ āĻāĻ āĻ āĻāĻļāĻāĻŋ āĻāĻĄāĻŧāĻŋāĻ¯āĻŧā§ āĻ¯āĻžāĻ¨āĨ¤
āĻ¸ā§āĻĨāĻŋāĻ¤āĻŋāĻļā§āĻ˛ āĻŦāĻŋāĻ¸ā§āĻ¤āĻžāĻ°ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻĻā§āĻ°ā§āĻ¤ āĻā§āĻŽāĻŋāĻāĻž
āĻ¸ā§āĻā§āĻ¯āĻžāĻŦāĻ˛ āĻĄāĻŋāĻĢāĻŋāĻāĻļāĻ¨ āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ā§ āĻā§āĻā§āĻ¸āĻ-āĻā§-āĻāĻŽā§āĻ āĻĒā§āĻ°āĻ¸ā§āĻ¸āĻŋāĻ āĻāĻ°āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ§āĻžāĻ¨ āĻŽā§āĻļāĻŋāĻ¨ āĻ˛āĻžāĻ°ā§āĻ¨āĻŋāĻ āĻŽāĻĄā§āĻ˛ (āĻāĻŦāĻ āĻāĻāĻ āĻŽāĻĄā§āĻ˛ āĻĄāĻžāĻ˛-āĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°ā§)āĨ¤ āĻāĻāĻŋ āĻāĻ āĻ§āĻ°āĻ¨ā§āĻ° āĻĄāĻŋāĻĒ āĻ˛āĻžāĻ°ā§āĻ¨āĻŋāĻ - āĻŽā§āĻļāĻŋāĻ¨ āĻ˛āĻžāĻ°ā§āĻ¨āĻŋāĻāĻ¯āĻŧā§āĻ° āĻāĻāĻāĻŋ āĻāĻĒāĻ¸ā§āĻ āĻ¯āĻž āĻ¨āĻŋāĻā§āĻā§ āĻāĻāĻāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻ āĻāĻžāĻ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨ āĻāĻ°āĻ¤ā§ āĻļā§āĻāĻžāĻ¯āĻŧ - āĻāĻ āĻā§āĻˇā§āĻ¤ā§āĻ°ā§ āĻāĻāĻāĻŋ āĻĒāĻžāĻ ā§āĻ¯ āĻāĻ¨āĻĒā§āĻāĻā§ āĻāĻāĻāĻŋ āĻāĻŋāĻ¤ā§āĻ° āĻāĻāĻāĻĒā§āĻā§ āĻ°ā§āĻĒāĻžāĻ¨ā§āĻ¤āĻ° āĻāĻ°āĻž āĻšāĻ¯āĻŧāĨ¤
āĻāĻ āĻāĻĻāĻžāĻšāĻ°āĻŖā§, āĻāĻŽāĻ°āĻž āĻāĻāĻāĻŋ āĻĄāĻŋāĻĢāĻŋāĻāĻļāĻ¨ āĻĒā§āĻ°ā§āĻŦā§āĻŦāĻŋāĻ˛āĻŋāĻ¸ā§āĻāĻŋāĻ āĻŽāĻĄā§āĻ˛ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻāĻŋ āĻ¯āĻž āĻā§āĻā§āĻ¸āĻ āĻĨā§āĻā§ āĻāĻŽā§āĻ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻ¤ā§ āĻāĻāĻāĻŋ āĻā§āĻ°āĻžāĻ¨ā§āĻ¸āĻĢāĻ°āĻŽāĻžāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°ā§āĨ¤
āĻ¯āĻžāĻāĻšā§āĻ āĻāĻŋāĻ¨ā§āĻ¤āĻž āĻāĻ°āĻŦā§āĻ¨ āĻ¨āĻž - āĻāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻŽāĻžāĻĻā§āĻ°āĻā§ āĻŽā§āĻļāĻŋāĻ¨ āĻ˛āĻžāĻ°ā§āĻ¨āĻŋāĻ āĻŽāĻĄā§āĻ˛ā§ āĻāĻŋāĻ¯āĻŧā§ āĻĒā§āĻ°āĻļāĻŋāĻā§āĻˇāĻŖ āĻĻā§āĻāĻ¯āĻŧāĻžāĻ° āĻĻāĻ°āĻāĻžāĻ° āĻ¨ā§āĻ (āĻ¯āĻĻāĻŋāĻ āĻāĻ°ā§ - āĻ¯āĻĻāĻŋ āĻāĻāĻŋ āĻāĻĒāĻ¨āĻžāĻ° āĻāĻŋāĻ¨āĻŋāĻ¸ āĻšāĻ¯āĻŧ - āĻāĻĒāĻ¨āĻŋ āĻ¸āĻŽā§āĻĒā§āĻ°ā§āĻŖ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨!)
āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§, āĻāĻŽāĻ°āĻž āĻāĻŽāĻžāĻĻā§āĻ° āĻĒāĻžāĻāĻĨāĻ¨ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻā§ Google-āĻāĻ° TensorFlow āĻāĻĒā§āĻ¨-āĻ¸ā§āĻ°ā§āĻ¸ āĻŽā§āĻļāĻŋāĻ¨ āĻ˛āĻžāĻ°ā§āĻ¨āĻŋāĻ āĻ˛āĻžāĻāĻŦā§āĻ°ā§āĻ°āĻŋ āĻĨā§āĻā§ āĻāĻāĻāĻŋ āĻĒā§āĻ°āĻžāĻ-āĻĒā§āĻ°āĻļāĻŋāĻā§āĻˇāĻŋāĻ¤ āĻŽāĻĄā§āĻ˛ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻ¤ā§ āĻ¯āĻžāĻā§āĻāĻŋ āĻāĻžāĻ°āĻŖ āĻāĻŽāĻžāĻĻā§āĻ° āĻāĻ¨ā§āĻ¯ ML āĻāĻāĻ¨āĻā§āĻ˛āĻŋ āĻĒā§āĻ°āĻžāĻ-āĻāĻŖāĻ¨āĻž āĻāĻ°āĻž āĻšāĻ¯āĻŧā§āĻā§āĨ¤
āĻāĻ°āĻ āĻ¸āĻ āĻŋāĻāĻāĻžāĻŦā§, āĻāĻŽāĻ°āĻž āĻāĻ¸āĻ˛ āĻāĻŽāĻāĻ˛ āĻŽāĻĄā§āĻ˛ā§āĻ° āĻāĻāĻāĻŋ āĻ āĻĒā§āĻāĻŋāĻŽāĻžāĻāĻ āĻāĻ°āĻž āĻā§āĻ°āĻžāĻ¸/āĻā§āĻ¨āĻ¸āĻ°āĻĢā§āĻ˛ā§ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ āĻĢāĻ°ā§āĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻāĻŋāĨ¤
āĻĒāĻžāĻāĻĨāĻ¨ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻ
đĻ āĻāĻĒāĻ¨āĻŋ āĻā§āĻāĻžāĻŦā§ āĻāĻ āĻā§āĻā§āĻ¸āĻ-āĻā§-āĻāĻŽā§āĻ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻāĻŋ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻŦā§āĻ¨ āĻāĻŦāĻ āĻĄāĻāĻžāĻ°āĻžāĻāĻ āĻāĻ°āĻŦā§āĻ¨ āĻ¤āĻžāĻ° āĻ¸āĻŽā§āĻĒā§āĻ°ā§āĻŖ āĻāĻ¯āĻŧāĻžāĻāĻĨā§āĻ°ā§ āĻā§āĻāĻā§ āĻĒāĻžāĻŦā§āĻ¨ āĻāĻŦāĻ āĻāĻāĻŋ Bacalhau āĻĄāĻā§āĻ¸ā§ āĻāĻŦāĻ āĻāĻ @BacalhauProject YouTube āĻāĻŋāĻĄāĻŋāĻāĻ¤ā§ āĻāĻžāĻ˛āĻžāĻ¨āĨ¤ đĻ āĻāĻĒāĻ¨āĻŋ āĻāĻ Google Collabs āĻ¨ā§āĻāĻŦā§āĻā§āĻ āĻāĻāĻŋ āĻāĻžāĻ˛āĻžāĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨
āĻāĻāĻžāĻ¨ā§ āĻ¸āĻŽā§āĻĒā§āĻ°ā§āĻŖ āĻĒāĻžāĻāĻĨāĻ¨ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻ!
import argparse from stable_diffusion_tf.stable_diffusion import Text2Image from PIL import Image import os parser = argparse.ArgumentParser(description="Stable Diffusion") parser.add_argument("--h",dest="height", type=int,help="height of the image",default=512) parser.add_argument("--w",dest="width", type=int,help="width of the image",default=512) parser.add_argument("--p",dest="prompt", type=str,help="Description of the image you want to generate",default="cat") parser.add_argument("--n",dest="numSteps", type=int,help="Number of Steps",default=50) parser.add_argument("--u",dest="unconditionalGuidanceScale", type=float,help="Number of Steps",default=7.5) parser.add_argument("--t",dest="temperature", type=int,help="Number of Steps",default=1) parser.add_argument("--b",dest="batchSize", type=int,help="Number of Images",default=1) parser.add_argument("--o",dest="output", type=str,help="Output Folder where to store the Image",default="./") args=parser.parse_args() height=args.height width=args.width prompt=args.prompt numSteps=args.numSteps unconditionalGuidanceScale=args.unconditionalGuidanceScale temperature=args.temperature batchSize=args.batchSize output=args.output generator = Text2Image( img_height=height, img_width=width, jit_compile=False, # You can try True as well (different performance profile) ) img = generator.generate( prompt, num_steps=numSteps, unconditional_guidance_scale=unconditionalGuidanceScale, temperature=temperature, batch_size=batchSize, ) for i in range(0,batchSize): pil_img = Image.fromarray(img[i]) image = pil_img.save(f"{output}/image{i}.png")
āĻāĻĒāĻ°ā§āĻ° āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻāĻŋ āĻā§āĻŦāĻ˛ āĻāĻāĻāĻŋ āĻā§āĻā§āĻ¸āĻ āĻĒā§āĻ°āĻŽā§āĻĒāĻ āĻāĻ¨āĻĒā§āĻ āĻāĻ°ā§āĻā§āĻŽā§āĻ¨ā§āĻ āĻāĻŦāĻ āĻāĻŋāĻā§ āĻ āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻāĻā§āĻāĻŋāĻ āĻĒāĻ°āĻžāĻŽāĻŋāĻ¤āĻŋ āĻā§āĻ°āĻšāĻŖ āĻāĻ°ā§ āĻāĻŦāĻ āĻ¤āĻžāĻ°āĻĒāĻ°ā§ āĻāĻžāĻāĻāĻžāĻ¯ā§āĻā§āĻ¤ āĻā§āĻ¨āĻ¸āĻ°āĻĢā§āĻ˛ā§ āĻ˛āĻžāĻāĻŦā§āĻ°ā§āĻ°āĻŋāĻ¤ā§ āĻāĻ˛ āĻāĻ°ā§ āĻāĻŦāĻŋ (āĻā§āĻ˛āĻŋ) āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻ¤ā§ āĻāĻŦāĻ āĻ¸ā§āĻā§āĻ˛āĻŋāĻā§ āĻāĻāĻāĻŋ āĻāĻāĻāĻĒā§āĻ āĻĢāĻžāĻāĻ˛ā§ āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°ā§ā§ˇ
āĻāĻāĻžāĻ¨ā§ āĻāĻ°āĻž āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻāĻžāĻ°ā§ āĻāĻ¤ā§āĻ¤ā§āĻ˛āĻ¨ āĻ¨ā§āĻā§āĻ° āĻŦāĻŋāĻāĻžāĻā§ āĻāĻā§ - āĻāĻāĻžāĻ¨ā§āĻ āĻŽā§āĻļāĻŋāĻ¨ āĻ˛āĻžāĻ°ā§āĻ¨āĻŋāĻ āĻŽāĻĄā§āĻ˛ āĻ¤āĻžāĻ° āĻāĻžāĻĻā§ āĻāĻ°ā§āĨ¤ đĒ
generator = Text2Image( img_height=height, img_width=width, jit_compile=False, ) img = generator.generate( prompt, num_steps=numSteps, unconditional_guidance_scale=unconditionalGuidanceScale, temperature=temperature, batch_size=batchSize, )
āĻĻāĻžāĻ°ā§āĻŖ, āĻāĻŽāĻ°āĻž āĻāĻāĻāĻŋ āĻā§āĻā§āĻ¸āĻ āĻĒā§āĻ°āĻŽā§āĻĒāĻ āĻĨā§āĻā§ āĻāĻŦāĻŋ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°āĻŋ, āĻāĻŋāĻ¨ā§āĻ¤ā§ āĻāĻŽ... āĻāĻ GPU-āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ā§āĻ¯āĻŧ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻāĻŋ āĻā§āĻĨāĻžāĻ¯āĻŧ āĻāĻžāĻ˛āĻžāĻ¤ā§ āĻšāĻŦā§..... đ¤đ¤
āĻ¯āĻĻāĻŋ āĻāĻāĻāĻŋ āĻāĻŋāĻ¨āĻŋāĻ¸ āĻĨāĻžāĻā§ āĻ¯ā§ āĻŦā§āĻ˛āĻāĻā§āĻāĻ¨ āĻĒā§āĻ°āĻ¯ā§āĻā§āĻ¤āĻŋ āĻ¸āĻšāĻāĻžāĻ¤āĻāĻžāĻŦā§ āĻāĻžāĻ˛ āĻāĻžāĻ āĻāĻ°ā§ āĻ¨āĻž, āĻ¤āĻž āĻšāĻ˛ āĻŦāĻĄāĻŧ āĻĄā§āĻāĻž āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻāĻ°āĻŖāĨ¤ āĻāĻāĻŋ āĻ¨āĻŋāĻ°ā§āĻāĻ°āĻ¯ā§āĻā§āĻ¯āĻ¤āĻž āĻāĻŦāĻ āĻ¸ā§āĻ¨ā§āĻ¸āĻ°āĻļāĻŋāĻĒ āĻĒā§āĻ°āĻ¤āĻŋāĻ°ā§āĻ§ā§āĻ° āĻŽāĻ¤ āĻ āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻļāĻā§āĻ¤āĻŋāĻļāĻžāĻ˛ā§ āĻŦā§āĻļāĻŋāĻˇā§āĻā§āĻ¯ āĻĒā§āĻ°āĻĻāĻžāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻŦāĻŋāĻ¤āĻ°āĻŖ āĻāĻ°āĻž āĻ¸āĻŋāĻ¸ā§āĻā§āĻŽā§āĻ° āĻāĻĒāĻ° āĻāĻŽā§āĻĒāĻŋāĻāĻāĻŋāĻ āĻāĻ°āĻā§āĻ° āĻāĻžāĻ°āĻŖā§āĨ¤
āĻā§āĻ āĻāĻĻāĻžāĻšāĻ°āĻŖā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻĒāĻ¨āĻžāĻ° āĻ¸ā§āĻĨāĻžāĻ¨ā§āĻ¯āĻŧ āĻŽā§āĻļāĻŋāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻž āĻ¸āĻŽā§āĻāĻŦ - āĻāĻ¸āĻ˛ā§ āĻāĻŽāĻŋ āĻāĻ āĻŦāĻŋāĻļā§āĻˇ āĻāĻĻāĻžāĻšāĻ°āĻŖāĻāĻŋ āĻāĻŽāĻžāĻ° (āĻāĻāĻŋ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻā§ āĻā§āĻŦ āĻ āĻ¸āĻ¨ā§āĻ¤ā§āĻˇā§āĻ) āĻŽā§āĻ¯āĻžāĻ āĻāĻŽ 1 āĻ āĻāĻžāĻ āĻāĻ°āĻ¤ā§ āĻĒā§āĻ°ā§āĻāĻŋ, āĻ¤āĻŦā§, āĻāĻāĻŋ āĻĢāĻ˛āĻžāĻĢāĻ˛ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻā§āĻŦ āĻĻā§āĻ°ā§āĻ āĻ āĻĒā§āĻā§āĻˇāĻž āĻāĻŋāĻ˛ (āĻā§āĻŦāĻŋāĻ˛ āĻā§āĻ¨āĻŋāĻ¸ā§āĻ° āĻā§āĻ˛āĻž āĻā§āĻ?) āĻ¸ā§āĻ¤āĻ°āĻžāĻ, āĻāĻāĻŦāĻžāĻ° āĻāĻĒāĻ¨āĻŋ āĻŦāĻĄāĻŧ āĻĄā§āĻāĻž āĻĒā§āĻ°āĻ¸ā§āĻ¸āĻŋāĻ āĻāĻ°āĻž āĻļā§āĻ°ā§ āĻāĻ°āĻ˛ā§, āĻāĻĒāĻ¨āĻžāĻ° āĻāĻ°āĻ āĻā§āĻ¯āĻžāĻ¸ā§āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ āĻšāĻŦā§ (āĻļā§āĻ˛ā§āĻˇā§āĻ° āĻāĻĻā§āĻĻā§āĻļā§āĻ¯ā§) āĻāĻŦāĻ āĻ¯āĻĻāĻŋ āĻāĻĒāĻ¨āĻžāĻ° āĻŦāĻžāĻĄāĻŧāĻŋāĻ° āĻāĻļā§āĻĒāĻžāĻļā§ āĻāĻāĻāĻŋ āĻĄā§āĻĄāĻŋāĻā§āĻā§āĻĄ āĻ¸āĻžāĻ°ā§āĻāĻžāĻ° āĻ¨āĻž āĻĨāĻžāĻā§, āĻ¤āĻžāĻšāĻ˛ā§ āĻāĻĒāĻ¨āĻžāĻā§ āĻāĻāĻāĻŋ āĻāĻžāĻ°ā§āĻā§āĻ¯āĻŧāĻžāĻ˛ āĻŽā§āĻļāĻŋāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻ¤ā§ āĻšāĻŦā§ āĻā§āĻ˛āĻžāĻāĻĄ āĻāĻŽā§āĻĒāĻŋāĻāĻāĻŋāĻ āĻĒā§āĻ˛ā§āĻ¯āĻžāĻāĻĢāĻ°ā§āĻŽāĨ¤
āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻāĻāĻŋ āĻā§āĻ¨ā§āĻĻā§āĻ°ā§āĻā§āĻ¤ āĻ¨āĻ¯āĻŧ, āĻāĻāĻŋ āĻ āĻĻāĻā§āĻˇāĻ - āĻāĻŖāĻ¨āĻž āĻŽā§āĻļāĻŋāĻ¨ āĻĨā§āĻā§ āĻĄā§āĻāĻž āĻ āĻāĻžāĻ¨āĻž āĻĻā§āĻ°āĻ¤ā§āĻŦā§āĻ° āĻāĻžāĻ°āĻŖā§ āĻāĻŦāĻ āĻāĻāĻŋ āĻĻā§āĻ°ā§āĻ¤ āĻŦā§āĻ¯āĻ¯āĻŧāĻŦāĻšā§āĻ˛ āĻšāĻ¤ā§ āĻĒāĻžāĻ°ā§āĨ¤ āĻāĻŽāĻŋ āĻāĻŽāĻ¨ āĻā§āĻ¨ā§ āĻĢā§āĻ°āĻŋ-āĻāĻžāĻ¯āĻŧāĻžāĻ° āĻā§āĻ˛āĻžāĻāĻĄ āĻāĻŽā§āĻĒāĻŋāĻāĻāĻŋāĻ āĻĒāĻ°āĻŋāĻˇā§āĻŦāĻž āĻā§āĻāĻā§ āĻĒāĻžāĻāĻ¨āĻŋ āĻ¯āĻž āĻāĻ° āĻāĻ¨ā§āĻ¯ GPU āĻĒā§āĻ°āĻ¸ā§āĻ¸āĻŋāĻ āĻ āĻĢāĻžāĻ° āĻāĻ°ā§ (āĻā§āĻ āĻāĻŋ āĻŦāĻ˛ā§āĻā§ āĻā§āĻ°āĻŋāĻĒā§āĻā§ āĻŽāĻžāĻāĻ¨āĻŋāĻ āĻ¨āĻŋāĻˇāĻŋāĻĻā§āĻ§..?) āĻāĻŦāĻ āĻĒāĻ°āĻŋāĻāĻ˛ā§āĻĒāĻ¨āĻžāĻā§āĻ˛āĻŋ āĻĒā§āĻ°āĻ¤āĻŋ āĻŽāĻžāĻ¸ā§ 400 āĻŽāĻžāĻ°ā§āĻāĻŋāĻ¨ āĻĄāĻ˛āĻžāĻ°ā§ āĻāĻ¸ā§āĻā§ (āĻ¨āĻž āĻ§āĻ¨ā§āĻ¯āĻŦāĻžāĻĻ)āĨ¤
āĻŦāĻžāĻāĻžāĻ˛āĻšāĻžāĻ !
āĻāĻžāĻā§āĻ¯āĻā§āĻ°āĻŽā§ āĻ¯āĻĻāĻŋāĻ, āĻāĻ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻžāĻā§āĻ˛āĻŋ āĻāĻŋāĻā§ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻ¯āĻž Bacalhau āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻāĻ°āĻžāĻ° āĻā§āĻˇā§āĻāĻž āĻāĻ°āĻā§āĨ¤ āĻĄā§āĻāĻž āĻĒā§āĻ°āĻ¸ā§āĻ¸āĻŋāĻ āĻāĻŦāĻ āĻāĻŖāĻ¨āĻžāĻā§ āĻ¸āĻāĻ˛ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻ¨ā§āĻŽā§āĻā§āĻ¤ āĻāĻŦāĻ āĻāĻĒāĻ˛āĻŦā§āĻ§ āĻāĻ°āĻž āĻāĻŦāĻ āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻāĻ°āĻŖā§āĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻĻā§āĻ°ā§āĻ¤ āĻāĻ°āĻž Bacalhau-āĻ¤ā§ āĻ¸āĻŽā§āĻāĻŦ, āĻĒā§āĻ°āĻĨāĻŽāĻ¤ - āĻāĻāĻžāĻ§āĻŋāĻ āĻ¨ā§āĻĄ āĻā§āĻĄāĻŧā§ āĻŦā§āĻ¯āĻžāĻ āĻĒā§āĻ°āĻ¸ā§āĻ¸āĻŋāĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°ā§ āĻāĻŦāĻ āĻĻā§āĻŦāĻŋāĻ¤ā§āĻ¯āĻŧāĻ¤ āĻ¯ā§āĻāĻžāĻ¨ā§ āĻĄā§āĻāĻž āĻŦāĻžāĻ¸ āĻāĻ°ā§ āĻ¸ā§āĻāĻžāĻ¨ā§ āĻĒā§āĻ°āĻ¸ā§āĻ¸āĻŋāĻ āĻ¨ā§āĻĄ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°ā§!
Bacalhau āĻāĻāĻĒāĻŋāĻāĻĢāĻāĻ¸, āĻĢāĻžāĻāĻ˛āĻāĻ¯āĻŧā§āĻ¨ āĻāĻŦāĻ āĻāĻ¯āĻŧā§āĻŦ3 āĻāĻ° āĻ āĻ¨ā§āĻ¤āĻ°ā§āĻ¨āĻŋāĻšāĻŋāĻ¤ āĻŦāĻŋāĻā§āĻ¨ā§āĻĻā§āĻ°ā§āĻāĻ°āĻŖ āĻŽāĻžāĻ¨āĻā§āĻ˛āĻŋāĻā§ āĻāĻ°āĻ āĻŦāĻŋāĻ¸ā§āĻ¤ā§āĻ¤āĻāĻžāĻŦā§ āĻĒāĻ°āĻŋāĻ¤ā§āĻ¯āĻžāĻ āĻ¨āĻž āĻāĻ°ā§ āĻĄā§āĻāĻžāĻ° āĻāĻĒāĻ° āĻ āĻĢ-āĻā§āĻāĻ¨ āĻāĻŖāĻ¨āĻž āĻ¸āĻā§āĻˇāĻŽ āĻāĻ°ā§ āĻĄā§āĻāĻž āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻāĻ°āĻŖā§āĻ° āĻāĻŦāĻŋāĻˇā§āĻ¯āĻ¤āĻā§ āĻāĻŖāĻ¤āĻžāĻ¨ā§āĻ¤ā§āĻ°āĻŋāĻ āĻāĻ°āĻ¤ā§ āĻ¸āĻšāĻžāĻ¯āĻŧāĻ¤āĻž āĻāĻ°āĻžāĻ° āĻ˛āĻā§āĻˇā§āĻ¯ā§ āĻ°āĻ¯āĻŧā§āĻā§ā§ˇ
Bacalhau āĻšāĻ˛ āĻāĻāĻāĻŋ āĻĒāĻŋāĻ¯āĻŧāĻžāĻ°-āĻā§-āĻĒāĻŋāĻ¯āĻŧāĻžāĻ° āĻāĻĒā§āĻ¨ āĻāĻŽā§āĻĒāĻŋāĻāĻā§āĻļāĻ¨ āĻ¨ā§āĻāĻāĻ¯āĻŧāĻžāĻ°ā§āĻ āĻ¯āĻž āĻ¸āĻ°ā§āĻŦāĻāĻ¨ā§āĻ¨, āĻ¸ā§āĻŦāĻā§āĻ āĻāĻŦāĻ āĻāĻā§āĻāĻŋāĻāĻāĻžāĻŦā§ āĻ¯āĻžāĻāĻžāĻāĻ¯ā§āĻā§āĻ¯ āĻāĻŖāĻ¨āĻž āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻā§āĻ˛āĻŋāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻĒā§āĻ˛ā§āĻ¯āĻžāĻāĻĢāĻ°ā§āĻŽ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻāĻ°ā§ āĻ¯ā§āĻāĻžāĻ¨ā§ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻāĻžāĻ°ā§āĻ°āĻž āĻāĻāĻĒāĻŋāĻāĻĢāĻāĻ¸ (āĻāĻŦāĻ āĻļā§āĻā§āĻ°āĻ āĻĢāĻžāĻāĻ˛āĻāĻ¯āĻŧā§āĻ¨) āĻ āĻ¸āĻā§āĻāĻŋāĻ¤ āĻĄā§āĻāĻž āĻ¸āĻš āĻ¯ā§āĻā§āĻ¨ā§ āĻĄā§āĻāĻžāĻ° āĻŦāĻŋāĻ°ā§āĻĻā§āĻ§ā§ āĻāĻžāĻ āĻšāĻŋāĻ¸āĻžāĻŦā§ āĻĄāĻāĻžāĻ° āĻāĻ¨ā§āĻā§āĻāĻ¨āĻžāĻ° āĻŦāĻž āĻāĻ¯āĻŧā§āĻŦ āĻ ā§āĻ¯āĻžāĻ¸ā§āĻŽā§āĻŦāĻ˛āĻŋ āĻāĻŦāĻŋ āĻāĻžāĻ˛āĻžāĻ¤ā§ āĻĒāĻžāĻ°ā§āĨ¤ āĻāĻŽāĻ¨āĻāĻŋ āĻāĻāĻŋāĻ° GPU āĻāĻžāĻā§āĻ° āĻāĻ¨ā§āĻ¯ āĻ¸āĻŽāĻ°ā§āĻĨāĻ¨ āĻ°āĻ¯āĻŧā§āĻā§ āĻāĻŦāĻ US$400 āĻŦāĻž āĻ¤āĻžāĻ° āĻŦā§āĻļāĻŋ āĻ¨āĻ¯āĻŧ!
Bacalhau āĻ¤ā§ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻ āĻāĻžāĻ˛āĻžāĻ¨ā§
āĻāĻ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻāĻŋ āĻāĻžāĻ˛āĻžāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯, āĻāĻŽāĻ°āĻž āĻāĻāĻŋāĻā§ Bacalhau-āĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°ā§āĻ° āĻāĻ¨ā§āĻ¯ Dockerise āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°āĻŋāĨ¤ āĻāĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻāĻāĻŋ āĻāĻ°āĻ¤ā§ āĻļāĻŋāĻāĻ¤ā§ āĻāĻžāĻ¨ āĻ¤āĻŦā§ āĻāĻĒāĻ¨āĻŋ āĻāĻāĻžāĻ¨ā§ āĻāĻŋāĻāĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ˛āĻāĻŋ āĻ āĻ¨ā§āĻ¸āĻ°āĻŖ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨ā§ˇ āĻ¤āĻžāĻ°āĻĒāĻ°ā§ āĻāĻŽāĻ°āĻž āĻāĻāĻŋāĻā§ Bacalhau CLI-āĻāĻ° āĻ¸āĻžāĻĨā§ āĻŽāĻžāĻ¤ā§āĻ° āĻāĻ āĻ˛āĻžāĻāĻ¨ā§āĻ° āĻā§āĻĄ āĻĻāĻŋāĻ¯āĻŧā§ āĻāĻžāĻ˛āĻžāĻ¤ā§ āĻĒāĻžāĻ°āĻŋ (āĻ āĻ¨ā§āĻ¯ āĻāĻ-āĻ˛āĻžāĻāĻ¨āĻžāĻ° āĻĻāĻŋāĻ¯āĻŧā§ Bacalhau āĻāĻ¨āĻ¸ā§āĻāĻ˛ āĻāĻ°āĻžāĻ° āĻĒāĻ°ā§):
bacalhau docker run --gpu 1 ghcr.io/bacalhau-project/examples/stable-diffusion-gpu:0.0.1 -- python main.py --o ./outputs --p "Rainbow Unicorn"
āĻ¯āĻĻāĻŋāĻ āĻāĻ āĻāĻĻāĻžāĻšāĻ°āĻŖā§, āĻāĻŽāĻŋ āĻāĻāĻāĻŋ āĻāĻāĻāĻāĻŋāĻāĻŋāĻĒāĻŋ āĻāĻ¨ā§āĻĄāĻĒāĻ¯āĻŧā§āĻ¨ā§āĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻ¤ā§ āĻ¯āĻžāĻā§āĻāĻŋ āĻ¯āĻž āĻāĻŽāĻžāĻā§ āĻāĻ āĻĄāĻāĻžāĻ°āĻžāĻāĻāĻĄ āĻ¸ā§āĻā§āĻ¯āĻžāĻŦāĻ˛ āĻĄāĻŋāĻĢāĻŋāĻāĻļāĻ¨ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻā§āĻ° āĻ¸āĻžāĻĨā§ āĻ¸āĻāĻ¯ā§āĻā§āĻ¤ āĻāĻ°ā§, āĻ¯āĻž āĻāĻŽāĻŋ āĻāĻĒāĻ¨āĻžāĻā§ āĻāĻ¨ā§āĻāĻŋāĻā§āĻ°ā§āĻļāĻ¨ āĻŦāĻŋāĻāĻžāĻā§ āĻĻā§āĻāĻžāĻŦ!
āĻ¯āĻĻāĻŋāĻ āĻāĻŽāĻŋ āĻāĻāĻžāĻ¨ā§ āĻ¨ā§āĻ āĻāĻ°āĻŦ, āĻāĻāĻŋ āĻĄā§āĻāĻž āĻāĻŖāĻ¨āĻž āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻāĻžāĻ˛āĻžāĻ¨ā§āĻ° āĻāĻāĻāĻŋ āĻļāĻā§āĻ¤āĻŋāĻļāĻžāĻ˛ā§ āĻāĻŦāĻ āĻ¨āĻŽāĻ¨ā§āĻ¯āĻŧ āĻāĻĒāĻžāĻ¯āĻŧ āĻ¯āĻž āĻāĻ¯āĻŧā§āĻŦ3 āĻŦāĻ¨ā§āĻ§ā§āĻ¤ā§āĻŦāĻĒā§āĻ°ā§āĻŖ - āĻāĻŽāĻ°āĻž āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻāĻ āĻāĻāĻāĻŋ āĻā§āĻ āĻŽāĻĄā§āĻ˛ā§āĻ° āĻŽāĻ§ā§āĻ¯ā§ āĻ¸ā§āĻŽāĻžāĻŦāĻĻā§āĻ§ āĻ¨āĻāĨ¤
āĻāĻ˛ā§āĻ¨ NFT āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻā§ āĻ¯āĻžāĻāĻšā§āĻ! :)
āĻ¸ā§āĻŽāĻžāĻ°ā§āĻ āĻā§āĻā§āĻ¤āĻŋ
NFT āĻ¸ā§āĻŽāĻžāĻ°ā§āĻ āĻā§āĻā§āĻ¤āĻŋāĻāĻŋ āĻāĻĒā§āĻ¨ āĻā§āĻĒā§āĻ˛āĻŋāĻ¨ā§āĻ° ERC721 āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§āĻ° āĻāĻĒāĻ° āĻāĻŋāĻ¤ā§āĻ¤āĻŋ āĻāĻ°ā§ āĻ¤ā§āĻ°āĻŋ āĻāĻŋāĻ¨ā§āĻ¤ā§ ERC721URIStorage āĻ¸āĻāĻ¸ā§āĻāĻ°āĻŖ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°ā§, āĻ¯āĻžāĻ° āĻŽāĻ§ā§āĻ¯ā§ āĻŽā§āĻāĻžāĻĄā§āĻāĻž āĻ¸ā§āĻā§āĻ¯āĻžāĻ¨ā§āĻĄāĻžāĻ°ā§āĻĄ āĻāĻā§āĻ¸āĻā§āĻ¨āĻļāĻ¨ āĻ°āĻ¯āĻŧā§āĻā§ (āĻ¤āĻžāĻ āĻāĻŽāĻ°āĻž āĻāĻŽāĻžāĻĻā§āĻ° IPFS-āĻ ā§āĻ¯āĻžāĻĄā§āĻ°ā§āĻ¸āĻĄ āĻŽā§āĻāĻžāĻĄā§āĻāĻž āĻĒāĻžāĻ¸ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°āĻŋ - āĻ¯āĻž āĻāĻŽāĻ°āĻž āĻā§āĻā§āĻ¤āĻŋāĻ¤ā§ NFT.Storage-āĻ āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°āĻŦ) .
āĻāĻ āĻŦā§āĻ¸ āĻāĻ¨ā§āĻā§āĻ°āĻžāĻā§āĻ āĻ āĻ¤āĻŋāĻ°āĻŋāĻā§āĻ¤āĻāĻžāĻŦā§ āĻāĻŽāĻžāĻĻā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§āĻ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻŋāĻ¤ āĻŽāĻŋāĻ¨ā§āĻ() āĻāĻŦāĻ āĻā§āĻ°āĻžāĻ¨ā§āĻ¸āĻĢāĻžāĻ°() āĻāĻ° āĻŽāĻ¤ā§ āĻĢāĻžāĻāĻļāĻ¨ āĻ¸āĻš āĻāĻāĻāĻŋ NFT āĻā§āĻā§āĻ¤āĻŋāĻ° āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻāĻžāĻ°ā§āĻ¯āĻāĻžāĻ°āĻŋāĻ¤āĻž āĻĻā§āĻ¯āĻŧāĨ¤
āĻāĻĒāĻ¨āĻŋ āĻ˛āĻā§āĻˇā§āĻ¯ āĻāĻ°āĻŦā§āĻ¨ āĻ¯ā§ āĻāĻŽāĻŋ āĻāĻŽāĻžāĻ° āĻ¸āĻžāĻŽāĻ¨ā§āĻ° āĻĒā§āĻ°āĻžāĻ¨ā§āĻ¤ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻĄā§āĻāĻž āĻāĻ¨āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻ¯āĻŧā§āĻāĻāĻŋ āĻā§āĻāĻžāĻ° āĻĢāĻžāĻāĻļāĻ¨ āĻ¯ā§āĻ āĻāĻ°ā§āĻāĻŋ āĻ¸ā§āĻāĻ¸āĻžāĻĨā§ āĻāĻāĻāĻŋ āĻāĻā§āĻ¨ā§āĻ āĻ¯āĻž āĻĒā§āĻ°āĻ¤āĻŋāĻŦāĻžāĻ° āĻāĻāĻāĻŋ āĻ¨āĻ¤ā§āĻ¨ NFT āĻŽāĻŋāĻ¨ā§āĻ āĻāĻ°āĻž āĻšāĻ˛ā§ āĻ āĻ¨-āĻā§āĻāĻ¨ āĻ¨āĻŋāĻ°ā§āĻāĻ¤ āĻšāĻŦā§āĨ¤ āĻāĻāĻŋ DApp āĻĨā§āĻā§ āĻ āĻ¨-āĻā§āĻāĻ¨ āĻāĻā§āĻ¨ā§āĻāĻā§āĻ˛āĻŋ āĻļā§āĻ¨āĻžāĻ° āĻā§āĻˇāĻŽāĻ¤āĻž āĻĻā§āĻ¯āĻŧā§ˇ
BacalhauFRC721.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@hardhat/console.sol"; contract BacalhauFRC721 is ERC721URIStorage { /** @notice Counter keeps track of the token ID number for each unique NFT minted in the NFT collection */ using Counters for Counters.Counter; Counters.Counter private _tokenIds; /** @notice This struct stores information about each NFT minted */ struct bacalhauFRC721NFT { address owner; string tokenURI; uint256 tokenId; } /** @notice Keeping an array for each of the NFT's minted on this contract allows me to get information on them all with a read-only front end call */ bacalhauFRC721NFT[] public nftCollection; /** @notice The mapping allows me to find NFT's owned by a particular wallet address. I'm only handling the case where an NFT is minted to an owner in this contract - but you'd need to handle others in a mainnet contract like sending to other wallets */ mapping(address => bacalhauFRC721NFT[]) public nftCollectionByOwner; /** @notice This event will be triggered (emitted) each time a new NFT is minted - which I will watch for on my front end in order to load new information that comes in about the collection as it happens */ event NewBacalhauFRC721NFTMinted( address indexed sender, uint256 indexed tokenId, string tokenURI ); /** @notice Creates the NFT Collection Contract with a Name and Symbol */ constructor() ERC721("Bacalhau NFTs", "BAC") { console.log("Hello Fil-ders! Now creating Bacalhau FRC721 NFT contract!"); } /** @notice The main function which will mint each NFT. The ipfsURI is a link to the ipfs content identifier hash of the NFT metadata stored on NFT.Storage. This data minimally includes name, description and the image in a JSON. */ function mintBacalhauNFT(address owner, string memory ipfsURI) public returns (uint256) { // get the tokenID for this new NFT uint256 newItemId = _tokenIds.current(); // Format info for saving to our array bacalhauFRC721NFT memory newNFT = bacalhauFRC721NFT({ owner: msg.sender, tokenURI: ipfsURI, tokenId: newItemId }); //mint the NFT to the chain _mint(owner, newItemId); //Set the NFT Metadata for this NFT _setTokenURI(newItemId, ipfsURI); _tokenIds.increment(); //Add it to our collection array & owner mapping nftCollection.push(newNFT); nftCollectionByOwner[owner].push(newNFT); // Emit an event on-chain to say we've minted an NFT emit NewBacalhauFRC721NFTMinted( msg.sender, newItemId, ipfsURI ); return newItemId; } /** * @notice helper function to display NFTs for frontends */ function getNFTCollection() public view returns (bacalhauFRC721NFT[] memory) { return nftCollection; } /** * @notice helper function to fetch NFT's by owner */ function getNFTCollectionByOwner(address owner) public view returns (bacalhauFRC721NFT[] memory){ return nftCollectionByOwner[owner]; }
āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ā§āĻ¯āĻŧāĻ¤āĻž
āĻāĻŽāĻŋ Filecoin āĻāĻžāĻ°ā§āĻā§āĻ¯āĻŧāĻžāĻ˛ āĻŽā§āĻļāĻŋāĻ¨ āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ āĻā§āĻ¸ā§āĻāĻ¨ā§āĻā§ āĻāĻ āĻā§āĻā§āĻ¤āĻŋāĻāĻŋ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°āĻŦ, āĻ¤āĻŦā§ āĻāĻĒāĻ¨āĻŋ āĻāĻ āĻā§āĻā§āĻ¤āĻŋāĻāĻŋ āĻĒāĻ˛āĻŋāĻāĻ¨, BSC, āĻ āĻĒāĻāĻŋāĻŽāĻŋāĻāĻŽ, āĻāĻ°ā§āĻŦāĻŋāĻā§āĻ°āĻžāĻŽ, āĻ ā§āĻ¯āĻžāĻāĻžāĻ˛āĻžāĻā§āĻ āĻāĻŦāĻ āĻāĻ°āĻ āĻ āĻ¨ā§āĻ āĻāĻŋāĻā§ āĻ¸āĻš āĻ¯ā§āĻā§āĻ¨ EVM-āĻ¸āĻžāĻŽāĻā§āĻāĻ¸ā§āĻ¯āĻĒā§āĻ°ā§āĻŖ āĻā§āĻāĻ¨ā§ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨āĨ¤ āĻāĻŽāĻ¨āĻāĻŋ āĻāĻĒāĻ¨āĻŋ āĻāĻāĻāĻŋ āĻŽāĻžāĻ˛ā§āĻāĻŋ-āĻā§āĻāĻ¨ āĻāĻ¨āĻāĻĢāĻāĻŋ (āĻāĻā§āĻāĻŋāĻ¤: āĻāĻ āĻ°ā§āĻĒā§ ) āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻ¤ā§ āĻāĻĒāĻ¨āĻžāĻ° āĻ¸āĻžāĻŽāĻ¨ā§āĻ° āĻĒā§āĻ°āĻžāĻ¨ā§āĻ¤ā§ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨!
āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ āĻā§āĻ¸ā§āĻāĻ¨ā§āĻā§ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°āĻ¤ā§ āĻāĻŽāĻžāĻĻā§āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ āĻšāĻŦā§
Hardhat āĻ¸āĻā§āĻā§ āĻ¸ā§āĻŽāĻžāĻ°ā§āĻ āĻā§āĻā§āĻ¤āĻŋ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨
āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ āĻā§āĻ¸ā§āĻāĻ¨ā§āĻā§ āĻāĻ āĻā§āĻā§āĻ¤āĻŋāĻāĻŋ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°āĻ¤ā§ āĻāĻŽāĻŋ āĻšāĻžāĻ°ā§āĻĄāĻšā§āĻ¯āĻžāĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻāĻŋāĨ¤
đ¸ āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ RPC āĻāĻŦāĻ āĻŦā§āĻ˛āĻāĻāĻā§āĻ¸āĻĒā§āĻ˛ā§āĻ°āĻžāĻ° āĻŦāĻŋāĻāĻ˛ā§āĻĒ:
āĻĒāĻžāĻŦāĻ˛āĻŋāĻ RPC āĻāĻ¨ā§āĻĄāĻĒāĻ¯āĻŧā§āĻ¨ā§āĻ
āĻŦā§āĻ˛āĻāĻāĻā§āĻ¸āĻĒā§āĻ˛ā§āĻ°āĻžāĻ°
https://filecoin-hyperspace.chainstacklabs.com/rpc/v0
https://hyperspace.filfox.info/rpc/v0
https://fvm.starboard.ventures/contracts/
https://rpc.ankr.com/filecoin_testnet
https://explorer.glif.io/?network=hyperspacenet
API āĻā§āĻ˛ā§āĻ¨ : beryx.zondax.ch
āĻāĻ¨āĻĢāĻŋāĻāĻžāĻ° āĻ¸ā§āĻ-āĻāĻĒā§āĻ° āĻāĻ¨ā§āĻ¯, āĻāĻŽāĻ°āĻž āĻāĻĒāĻ˛āĻŦā§āĻ§ āĻ¯ā§ āĻā§āĻ¨ā§ āĻĒāĻžāĻŦāĻ˛āĻŋāĻ RPC āĻāĻ¨ā§āĻĄāĻĒāĻ¯āĻŧā§āĻ¨ā§āĻ āĻĨā§āĻā§ āĻŦā§āĻā§ āĻ¨āĻŋāĻ¤ā§ āĻĒāĻžāĻ°āĻŋāĨ¤
hardhat.config.ts
import '@nomicfoundation/hardhat-toolbox'; import { config as dotenvConfig } from 'dotenv'; import { HardhatUserConfig } from 'hardhat/config'; import { resolve } from 'path'; //Import our customised tasks // import './pages/api/hardhat/tasks'; const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || './.env'; dotenvConfig({ path: resolve(__dirname, dotenvConfigPath) }); // Ensure that we have all the environment variables we need. const walletPrivateKey: string | undefined = process.env.WALLET_PRIVATE_KEY; if (!walletPrivateKey) { throw new Error('Please set your Wallet private key in a .env file'); } const config: HardhatUserConfig = { solidity: '0.8.17', defaultNetwork: 'filecoinHyperspace', networks: { hardhat: {}, filecoinHyperspace: { url: 'https://api.hyperspace.node.glif.io/rpc/v1', chainId: 3141, accounts: [process.env.WALLET_PRIVATE_KEY ?? 'undefined'], }, // bleeding edge often-reset FVM testnet filecoinWallaby: { url: 'https://wallaby.node.glif.io/rpc/v0', chainId: 31415, accounts: [process.env.WALLET_PRIVATE_KEY ?? 'undefined'], //explorer: https://wallaby.filscan.io/ and starboard }, }, // I am using the path mapping so I can keep my hardhat deployment within the /pages folder of my DApp and therefore access the contract ABI for use on my frontend paths: { root: './pages/api/hardhat', tests: './pages/api/hardhat/tests', //who names a directory in the singular?!!! Grammarly would not be happy cache: './pages/api/hardhat/cache', }, }; export default config;
āĻāĻŦāĻ āĻ¸ā§āĻŽāĻžāĻ°ā§āĻ āĻāĻ¨ā§āĻā§āĻ°āĻžāĻā§āĻ āĻĄāĻŋāĻĒā§āĻ˛āĻ¯āĻŧ āĻāĻ°āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻŽāĻ°āĻž āĻāĻāĻāĻŋ āĻĄāĻŋāĻĒā§āĻ˛ā§āĻ¯āĻŧ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻŋ - āĻŽāĻ¨ā§ āĻ°āĻžāĻāĻŦā§āĻ¨ āĻ¯ā§ āĻāĻŽāĻŋ āĻāĻāĻžāĻ¨ā§ āĻāĻ¯āĻŧāĻžāĻ˛ā§āĻ āĻ ā§āĻ¯āĻžāĻĄā§āĻ°ā§āĻ¸āĻāĻŋ āĻ¸ā§āĻŦāĻžāĻā§āĻˇāĻ°āĻāĻžāĻ°ā§ (āĻŽāĻžāĻ˛āĻŋāĻ) āĻšāĻŋāĻ¸āĻžāĻŦā§ āĻ¸ā§āĻ āĻāĻ°āĻāĻŋ - āĻ˛ā§āĻāĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ FEVM-āĻ āĻāĻŋāĻā§ āĻŽā§āĻ¯āĻžāĻĒāĻŋāĻ āĻ¤ā§āĻ°ā§āĻāĻŋ āĻāĻāĻ¨āĻ āĻāĻžāĻ āĻāĻ°āĻž āĻšāĻā§āĻā§ āĻ¯āĻž āĻšāĻ¤ā§ āĻĒāĻžāĻ°ā§ āĻāĻŋāĻā§ āĻ āĻĻā§āĻā§āĻ¤ āĻāĻāĻ°āĻŖāĨ¤
deploy/deployBacalhauFRC721.ts
import hre from 'hardhat'; import type { BacalhauFRC721 } from '../typechain-types/contracts/BacalhauFRC721'; import type { BacalhauFRC721__factory } from '../typechain-types/factories/contracts/BacalhauFRC721__factory'; async function main() { console.log('Bacalhau721 deploying....'); // !!!needed as hardhat's default does not map correctly to the FEVM const owner = new hre.ethers.Wallet( process.env.WALLET_PRIVATE_KEY || 'undefined', hre.ethers.provider ); const bacalhauFRC721Factory: BacalhauFRC721__factory = < BacalhauFRC721__factory > await hre.ethers.getContractFactory('BacalhauFRC721', owner); const bacalhauFRC721: BacalhauFRC721 = <BacalhauFRC721>( await bacalhauFRC721Factory.deploy() ); await bacalhauFRC721.deployed(); console.log('bacalhauFRC721 deployed to ', bacalhauFRC721.address); // optionally log to a file here } main().catch((error) => { console.error(error); process.exitCode = 1; });
āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°āĻ¤ā§, āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻāĻŋāĻ¤ āĻā§āĻĄāĻāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°ā§ āĻāĻžāĻ°ā§āĻŽāĻŋāĻ¨āĻžāĻ˛ā§ āĻāĻĒāĻ°ā§āĻ° āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻāĻŋ āĻāĻžāĻ˛āĻžāĻ¨ (NB: āĻ¯ā§āĻšā§āĻ¤ā§ āĻāĻŽāĻ°āĻž āĻāĻŽāĻžāĻĻā§āĻ° āĻāĻ¨āĻĢāĻŋāĻāĻžāĻ°ā§ filecoinHyperspace-āĻ āĻĄāĻŋāĻĢāĻ˛ā§āĻ āĻ¨ā§āĻāĻāĻ¯āĻŧāĻžāĻ°ā§āĻ āĻ¸ā§āĻ āĻāĻ°ā§āĻāĻŋ, āĻ¨ā§āĻāĻāĻ¯āĻŧāĻžāĻ°ā§āĻā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻĒāĻ¤āĻžāĻāĻž āĻĒāĻžāĻ¸ āĻāĻ°āĻžāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ āĻ¨ā§āĻ āĻ¯āĻĻāĻŋāĻ āĻāĻāĻŋ āĻ¨ā§āĻā§ āĻĻā§āĻāĻžāĻ¨ā§ āĻšāĻ¯āĻŧā§āĻā§)
> cd ./pages/hardhat/deploy/
npx hardhat run ./deployBacalhauFRC721.ts --network filecoinHyperspace
āĻāĻĻāĻ¯āĻžāĻĒāĻ¨! āĻāĻŽāĻ°āĻž āĻāĻāĻŽāĻžāĻ¤ā§āĻ° āĻĢāĻžāĻāĻ˛āĻāĻ¯āĻŧā§āĻ¨ āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ āĻā§āĻ¸ā§āĻāĻ¨ā§āĻā§ āĻāĻŽāĻžāĻĻā§āĻ° NFT āĻā§āĻā§āĻ¤āĻŋ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻāĻ°ā§āĻāĻŋ!
āĻ¸ā§āĻ¨ā§āĻĻāĻ° āĻ āĻāĻļā§āĻ° āĻāĻĒāĻ° āĻāĻšā§... āĻāĻŦāĻ āĻ¸ā§āĻ āĻāĻ āĻžāĻ āĻ¯āĻž āĻāĻāĻžāĻ¨ā§ āĻ¸āĻŦ āĻāĻāĻ¸āĻžāĻĨā§ āĻ§āĻ°ā§ āĻ°āĻžāĻā§ :)
āĻ¸āĻžāĻŽāĻ¨ā§āĻ° āĻĒā§āĻ°āĻžāĻ¨ā§āĻ¤āĻāĻŋ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻ¤ā§, āĻāĻŽāĻŋ NextJS āĻāĻŦāĻ Typescript āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻāĻŋāĨ¤ āĻ¯āĻĻāĻŋāĻ, āĻ¸āĻ¤ā§āĻ¯āĻŋ āĻāĻĨāĻž āĻŦāĻ˛āĻ¤ā§ - āĻāĻŽāĻŋ āĻ¨ā§āĻā§āĻ¸āĻāĻā§āĻāĻ¸-āĻāĻ° SSR (āĻ¸āĻžāĻ°ā§āĻāĻžāĻ°-āĻ¸āĻžāĻāĻĄ āĻ°ā§āĻ¨ā§āĻĄāĻžāĻ°āĻŋāĻ) āĻŦā§āĻļāĻŋāĻˇā§āĻā§āĻ¯āĻā§āĻ˛āĻŋāĻ° āĻā§āĻ¨āĻ āĻ¸ā§āĻŦāĻŋāĻ§āĻž āĻ¨āĻŋāĻā§āĻāĻŋ āĻ¨āĻž āĻāĻŦāĻ āĻāĻŽāĻŋ āĻ¤āĻžāĻĻā§āĻ° āĻĒā§āĻˇā§āĻ āĻž āĻ°āĻžāĻāĻāĻŋāĻāĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻŋ āĻ¨āĻž (āĻ¯ā§āĻšā§āĻ¤ā§ āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻāĻāĻ-āĻĒā§āĻˇā§āĻ āĻžāĻ° Dapp), āĻ¤āĻžāĻ āĻāĻĒāĻ¨āĻŋ āĻ¸āĻ¤ā§āĻ¯āĻŋāĻ āĻ¯ā§āĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨ āĻā§āĻ¯āĻžāĻ¨āĻŋāĻ˛āĻž āĻ°āĻŋāĻ ā§āĻ¯āĻžāĻā§āĻ āĻ¸ā§āĻ āĻāĻĒ āĻ¸āĻš (āĻŦāĻž āĻ āĻŦāĻļā§āĻ¯āĻ āĻāĻĒāĻ¨āĻžāĻ° āĻĒāĻāĻ¨ā§āĻĻā§āĻ° āĻ¯ā§āĻā§āĻ¨ āĻĢā§āĻ°ā§āĻŽāĻāĻ¯āĻŧāĻžāĻ°ā§āĻ!)
āĻāĻžāĻāĻĒāĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻā§āĻ° āĻāĻ¨ā§āĻ¯ ... āĻāĻžāĻ˛, āĻāĻŽāĻŋ āĻāĻāĻŋāĻā§ āĻāĻŋāĻā§āĻāĻž āĻ¤āĻžāĻĄāĻŧāĻžāĻšā§āĻĄāĻŧā§ āĻāĻ°ā§ āĻ¤ā§āĻ°āĻŋ āĻāĻ°ā§āĻāĻŋ āĻāĻŦāĻ āĻ¸ā§āĻŦā§āĻāĻžāĻ° āĻāĻ°āĻ¤ā§ āĻšāĻŦā§ āĻāĻāĻŋ āĻāĻžāĻāĻĒāĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻā§āĻ° āĻā§āĻŦ āĻāĻžāĻ˛ āĻāĻĻāĻžāĻšāĻ°āĻŖ āĻ¨āĻ¯āĻŧ - āĻ¯āĻĻāĻŋāĻ āĻāĻžāĻ°āĻā§āĻ˛āĻŋ āĻā§āĻļāĻŋ āĻŦāĻ˛ā§ āĻŽāĻ¨ā§ āĻšāĻā§āĻā§... ;)
Anyhoo - āĻāĻ āĻŦāĻŋāĻāĻžāĻā§āĻ° āĻŽā§āĻ˛ āĻĒāĻ¯āĻŧā§āĻ¨ā§āĻāĻāĻŋ āĻāĻĒāĻ¨āĻžāĻā§ āĻĻā§āĻāĻžāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻ¨āĻ¯āĻŧ āĻ¯ā§ āĻā§āĻāĻžāĻŦā§ āĻāĻāĻāĻŋ āĻĢā§āĻ°āĻ¨ā§āĻ āĻāĻ¨ā§āĻĄ āĻā§āĻĄ āĻāĻ°āĻ¤ā§ āĻšāĻ¯āĻŧ, āĻ¤āĻŦā§ āĻāĻĒāĻ¨āĻžāĻā§ āĻĻā§āĻāĻžāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻŋāĻāĻžāĻŦā§ āĻ¸ā§āĻŽāĻžāĻ°ā§āĻ āĻā§āĻā§āĻ¤āĻŋāĻ° āĻ¸āĻžāĻĨā§ āĻāĻ¨ā§āĻāĻžāĻ°āĻ ā§āĻ¯āĻžāĻā§āĻ āĻāĻ°āĻ¤ā§ āĻšāĻ¯āĻŧ, Bacalhau (āĻāĻŽāĻžāĻĻā§āĻ° āĻ¸ā§āĻĨāĻŋāĻ¤āĻŋāĻļā§āĻ˛ āĻĄāĻŋāĻĢāĻŋāĻāĻļāĻ¨ āĻāĻŽāĻāĻ˛ āĻŽāĻĄā§āĻ˛ āĻ¸āĻš) āĻāĻŦāĻ āĻ āĻŦāĻļā§āĻ¯āĻ, NFT.Storage - # NotOnIPFSNotYourNFT.
[āĻāĻ°ā§āĻ¨: āĻāĻāĻāĻŋ āĻĢā§āĻ˛ā§ āĻāĻžāĻ°ā§āĻ āĻĄāĻžāĻ¯āĻŧāĻžāĻā§āĻ°āĻžāĻŽ āĻ¤ā§āĻ°āĻŋ āĻāĻ°ā§āĻ¨]
āĻāĻŽā§āĻāĻžāĻ° - āĻāĻ¸ā§āĻ¨ āĻĻā§āĻāĻŋ āĻāĻŋāĻāĻžāĻŦā§ āĻāĻŽāĻ°āĻž āĻā§āĻĄā§ āĻāĻāĻŋ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ āĻāĻ°āĻŋ!
Bacalhau-āĻāĻ° āĻāĻ¨ā§āĻ¯ āĻĢā§āĻ°āĻ¨ā§āĻ-āĻāĻ¨ā§āĻĄ API āĻāĻ¨ā§āĻĄāĻĒāĻ¯āĻŧā§āĻ¨ā§āĻ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻž āĻĒā§āĻ°āĻā§āĻļāĻ˛ā§ āĻ˛ā§āĻ āĻŽāĻžāĻ°ā§āĻ¸āĻĄā§āĻ¨ā§āĻ° āĻāĻ āĻĒā§āĻ°āĻāĻ˛ā§āĻĒ āĻĒā§āĻ°āĻ¤āĻŋāĻŦā§āĻĻāĻ¨ā§ āĻ¨āĻĨāĻŋāĻā§āĻā§āĻ¤ āĻāĻ°āĻž āĻšāĻ¯āĻŧā§āĻā§āĨ¤
API āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ā§ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻāĻ āĻŦā§āĻ˛āĻā§ āĻ¨āĻĨāĻŋāĻā§āĻā§āĻ¤ āĻ¸ā§āĻĨāĻŋāĻ¤āĻŋāĻļā§āĻ˛ āĻŦāĻŋāĻā§āĻā§āĻ°āĻŖ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻā§āĻ˛āĻŋāĻ¤ā§ āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ āĻāĻāĻžāĻ¤ āĻāĻ°ā§, āĻ¤āĻŦā§, āĻĻāĻ˛āĻāĻŋ āĻāĻāĻŋāĻā§ āĻāĻ°āĻ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ API-āĻ āĻĒā§āĻ°āĻ¸āĻžāĻ°āĻŋāĻ¤ āĻāĻ°āĻžāĻ° āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ§ā§āĻ¨ āĻ°āĻ¯āĻŧā§āĻā§ āĻ¯āĻžāĻ¤ā§ āĻāĻĒāĻ¨āĻŋ āĻ¯ā§āĻā§āĻ¨āĻ āĻāĻĻāĻžāĻšāĻ°āĻŖ āĻāĻ˛ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨, āĻāĻŦāĻ āĻāĻāĻāĻŋ HTTP āĻĨā§āĻā§ āĻāĻĒāĻ¨āĻžāĻ° āĻ¨āĻŋāĻā§āĻ° āĻ¨āĻŋāĻ¯āĻŧā§āĻāĻŋāĻ¤ āĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻāĻā§āĻ˛āĻŋāĻ REST APIāĨ¤ āĻāĻāĻžāĻ¨ā§ āĻŦāĻž FilecoinProject āĻ¸ā§āĻ˛ā§āĻ¯āĻžāĻā§āĻ° #bacalhau āĻā§āĻ¯āĻžāĻ¨ā§āĻ˛ā§ āĻāĻāĻŋāĻ° āĻāĻĒāĻ° āĻ¨āĻāĻ° āĻ°āĻžāĻā§āĻ¨āĨ¤
>run/test in terminal
curl -XPOST -d '{"prompt": "rainbow unicorn"}' 'http://dashboard.bacalhau.org:1000/api/v1/stablediffusion';
>react / typescript code
import { CID } from 'multiformats/cid'; export const callBacalhauJob = async (promptInput: string) => { //Bacalahau HTTP Stable Diffusion Endpoint const url = 'http://dashboard.bacalhau.org:1000/api/v1/stablediffusion'; const headers = { 'Content-Type': 'application/x-www-form-urlencoded', }; const data = { prompt: promptInput, //The user text prompt! }; /* FETCH FROM BACALHAU ENDPOINT */ const cid = await fetch(url, { method: 'POST', body: JSON.stringify(data), headers: headers, }) .then(async (res) => { let body = await res.json(); if (body.cid) { /* Bacalhau returns a V0 CID which we want to convert to a V1 CID for easier usage with http gateways (ie. displaying the image on web), so I'm using the IPFS multiformats package to convert it here */ return CID.parse(body.cid).toV1().toString(); } }) .catch((err) => { console.log('error in bac job', err); }); return cid; };
āĻāĻ āĻĢāĻžāĻāĻļāĻ¨āĻāĻŋ āĻāĻāĻāĻŋ āĻāĻāĻĒāĻŋāĻāĻĢāĻāĻ¸ āĻ¸āĻŋāĻāĻāĻĄāĻŋ (āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻļāĻ¨āĻžāĻā§āĻ¤āĻāĻžāĻ°ā§) āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻāĻ°āĻŦā§ āĻ¯āĻž āĻ¨ā§āĻā§āĻ° āĻŽāĻ¤ āĻāĻāĻāĻŋ āĻĢā§āĻ˛ā§āĻĄāĻžāĻ° āĻāĻžāĻ āĻžāĻŽā§ āĻ¸āĻšāĨ¤ āĻ¤āĻžāĻ°āĻĒāĻ°ā§ āĻāĻŦāĻŋāĻāĻŋ /outputs/image0.png
āĻāĻ° āĻ
āĻ§ā§āĻ¨ā§ āĻĒāĻžāĻāĻ¯āĻŧāĻž āĻ¯āĻžāĻŦā§āĨ¤
đĄ āĻāĻāĻžāĻ¨ā§ āĻā§āĻ˛āĻŋāĻ āĻāĻ°ā§ āĻ¨āĻŋāĻā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻŋ āĻĻā§āĻā§āĻ¨ ! đĄ
āĻāĻšāĻš āĻ°ā§āĻāĻ¨āĻŦā§ āĻāĻāĻ¨āĻŋāĻāĻ°ā§āĻ¨... āĻāĻŋ āĻāĻžāĻ˛ā§ āĻ˛āĻžāĻā§ āĻ¨āĻž!
NFT.Storage āĻšāĻ˛ āĻāĻāĻāĻŋ āĻĒāĻžāĻŦāĻ˛āĻŋāĻ āĻā§āĻĄ (āĻāĻ°āĻĢā§ āĻĢā§āĻ°āĻŋ) āĻ¯āĻž āĻāĻžāĻāĻžāĻ¸ā§āĻā§āĻ°āĻŋāĻĒā§āĻ āĻŦāĻž HTTP SDK āĻ¸āĻš IPFS āĻāĻŦāĻ Filecoin-āĻ āĻ¸ā§āĻĨāĻžāĻ¯āĻŧā§āĻāĻžāĻŦā§ NFT āĻŽā§āĻāĻžāĻĄā§āĻāĻž āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°āĻž āĻ¸āĻšāĻ āĻāĻ°ā§āĨ¤
NFT āĻŽā§āĻāĻžāĻĄā§āĻāĻž āĻšāĻ˛ āĻāĻāĻāĻŋ JSON āĻ¨āĻĨāĻŋ āĻ¯āĻž āĻ¨ā§āĻā§āĻ° āĻāĻĻāĻžāĻšāĻ°āĻŖā§āĻ° āĻŽāĻ¤ā§ āĻĻā§āĻāĻ¤ā§ - āĻ¯āĻž āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ āĻāĻĒā§āĻ¨ āĻā§āĻĒā§āĻ˛āĻŋāĻ¨ āĻĄāĻā§āĻ¸ āĻĨā§āĻā§ āĻ¨ā§āĻāĻ¯āĻŧāĻž āĻšāĻ¯āĻŧā§āĻā§:
āĻāĻ¨āĻāĻĢāĻāĻŋ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ, āĻāĻāĻž āĻŽāĻ¨ā§ āĻ°āĻžāĻāĻž āĻā§āĻ°ā§āĻ¤ā§āĻŦāĻĒā§āĻ°ā§āĻŖ āĻ¯ā§ āĻāĻĒāĻ¨āĻŋ āĻŽā§āĻāĻžāĻĄā§āĻāĻž āĻ āĻ¨-āĻā§āĻāĻ¨ā§ (āĻ¯āĻž āĻŦāĻĄāĻŧ āĻĢāĻžāĻāĻ˛ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻ¨āĻŋāĻˇā§āĻ§āĻŽā§āĻ˛āĻāĻāĻžāĻŦā§ āĻŦā§āĻ¯āĻ¯āĻŧāĻŦāĻšā§āĻ˛ āĻšāĻ¯āĻŧā§ āĻāĻ āĻ¤ā§ āĻĒāĻžāĻ°ā§) āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°āĻā§āĻ¨ āĻ¨āĻž, āĻ¤āĻžāĻšāĻ˛ā§ āĻāĻāĻāĻŋ āĻā§āĻā§āĻ¨ā§āĻ° 'āĻ¨āĻ¨-āĻĢāĻžāĻā§āĻāĻŋāĻŦāĻŋāĻ˛āĻŋāĻāĻŋ'-āĻāĻ° āĻ¸āĻžāĻĨā§ āĻ¸āĻžāĻŽāĻā§āĻāĻ¸ā§āĻ¯ āĻāĻ°āĻžāĻ° āĻāĻ¨ā§āĻ¯, āĻāĻĒāĻ¨āĻžāĻ° āĻ¸ā§āĻā§āĻ°ā§āĻ āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ āĻ¯āĻž āĻ āĻŦāĻŋāĻāĻ˛, āĻ¨āĻŋāĻ°ā§āĻāĻ°āĻ¯ā§āĻā§āĻ¯ āĻāĻŦāĻ āĻ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ā§āĻ¯āĻŧāĨ¤
āĻ¯āĻĻāĻŋ āĻāĻĒāĻ¨āĻžāĻ° NFT-āĻ āĻāĻĒāĻ°ā§āĻ° āĻāĻĻāĻžāĻšāĻ°āĻŖā§āĻ° āĻŽāĻ¤ā§ āĻāĻāĻāĻŋ āĻ āĻŦāĻ¸ā§āĻĨāĻžāĻ¨-āĻāĻŋāĻ¤ā§āĻ¤āĻŋāĻ āĻ āĻŋāĻāĻžāĻ¨āĻž āĻĨāĻžāĻā§, āĻ¤āĻžāĻšāĻ˛ā§ āĻŦāĻŋāĻā§āĻ°āĻ¯āĻŧā§āĻ° āĻĒāĻ°ā§ āĻāĻ āĻ āĻŦāĻ¸ā§āĻĨāĻžāĻ¨ā§āĻ° āĻĒāĻĨāĻāĻŋ āĻ¸ā§āĻ¯ā§āĻāĻ āĻāĻāĻ āĻāĻ°āĻž āĻŽā§āĻāĻžāĻŽā§āĻāĻŋ āĻ¸āĻšāĻ, āĻŽāĻžāĻ¨ā§ āĻāĻĒāĻ¨āĻŋ āĻ¯ā§ āĻāĻ¨āĻāĻĢāĻāĻŋ āĻāĻŋāĻ¨ā§āĻā§āĻ¨ āĻ¤āĻž āĻ¸āĻŽā§āĻĒā§āĻ°ā§āĻŖ āĻāĻŋāĻ¨ā§āĻ¨ āĻāĻŋāĻā§ āĻšāĻ¯āĻŧā§ āĻā§āĻā§ - āĻŦāĻž āĻā§āĻˇā§āĻ¤ā§āĻ°ā§ āĻāĻāĻāĻŋ āĻāĻā§āĻˇāĻ°āĻŋāĻ āĻ°āĻžāĻ āĻāĻžāĻ¨ āĻ¨ā§āĻā§ āĻ¯ā§āĻāĻžāĻ¨ā§ āĻāĻ¨āĻāĻĢāĻāĻŋ āĻ¸ā§āĻ°āĻˇā§āĻāĻž āĻ°āĻžāĻāĻā§āĻ˛āĻŋāĻ° āĻāĻŦāĻŋāĻ° āĻāĻ¨ā§āĻ¯ āĻļāĻŋāĻ˛ā§āĻĒ āĻāĻŋāĻ¤ā§āĻ°āĻā§āĻ˛āĻŋāĻā§ āĻ¸ā§āĻāĻ āĻāĻāĻ āĻāĻ°ā§āĻā§āĻ¨ā§ˇ
āĻāĻŋāĻā§ āĻāĻŽāĻ¨āĻāĻŋ āĻā§āĻ˛āĻž Zeppelin āĻ¸āĻŽā§āĻĒāĻ°ā§āĻā§ āĻ¸āĻ¤āĻ°ā§āĻ!
NFT.Storage āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻžāĻ° āĻ āĻ°ā§āĻĨ āĻšāĻ˛ āĻāĻŽāĻ°āĻž āĻāĻŽāĻžāĻĻā§āĻ° āĻŽā§āĻāĻžāĻĄā§āĻāĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ā§āĻ¯āĻŧ IPFS āĻĢāĻžāĻāĻ˛ CID ( āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ - āĻ āĻŦāĻ¸ā§āĻĨāĻžāĻ¨ āĻ¨āĻ¯āĻŧ - āĻāĻāĻĄāĻŋ āĻāĻ¨āĻāĻŋāĻĢāĻžāĻ¯āĻŧāĻžāĻ°) āĻĒāĻžāĻ āĻ¯āĻž āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° IPFS-āĻ āĻĒāĻŋāĻ¨ āĻāĻ°āĻž āĻšāĻ¯āĻŧ āĻ¨āĻž āĻāĻŋāĻ¨ā§āĻ¤ā§ āĻ¤āĻžāĻ°āĻĒāĻ°ā§ āĻ āĻ§ā§āĻ¯āĻŦāĻ¸āĻžāĻ¯āĻŧā§āĻ° āĻāĻ¨ā§āĻ¯ Filecoin-āĻ āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°āĻž āĻšāĻ¯āĻŧā§ˇ āĻāĻĒāĻ¨āĻžāĻā§ āĻā§āĻŦāĻ˛ āĻ¸āĻžāĻāĻ¨ āĻāĻĒ āĻāĻ°āĻ¤ā§ āĻšāĻŦā§ NFT.Storage āĻāĻŦāĻ āĻāĻāĻŋāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ API āĻā§ (āĻāĻĒāĻ¨āĻžāĻ° .env āĻĢāĻžāĻāĻ˛ā§ āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°āĻ¤ā§) āĻĒāĻžāĻ¨āĨ¤
.env example
NEXT_PUBLIC_NFT_STORAGE_API_KEY=xxx
āĻāĻŽāĻžāĻĻā§āĻ° āĻāĻāĻžāĻ āĻ¨āĻŋāĻļā§āĻāĻŋāĻ¤ āĻāĻ°āĻ¤ā§ āĻšāĻŦā§ āĻ¯ā§ āĻāĻŽāĻ°āĻž āĻāĻāĻāĻŋ āĻ¸āĻ āĻŋāĻāĻāĻžāĻŦā§ āĻāĻ āĻŋāĻ¤ āĻŽā§āĻāĻžāĻĄā§āĻāĻž JSON āĻ¤ā§āĻ°āĻŋ āĻāĻ°ā§āĻāĻŋ - āĻāĻžāĻ°āĻŖ FVM-āĻāĻ° (āĻāĻāĻ¨āĻ!) NFT āĻŽāĻžāĻ°ā§āĻā§āĻāĻĒā§āĻ˛ā§āĻ¸ āĻ¨ā§āĻ... āĻāĻŽāĻ°āĻž āĻ¨āĻŋāĻļā§āĻāĻŋāĻ¤ āĻāĻ°āĻ¤ā§ āĻāĻžāĻ āĻ¯ā§ āĻ¯āĻāĻ¨ āĻāĻāĻŋ āĻā§āĻšā§āĻ¤ āĻšāĻ¯āĻŧ āĻ¤āĻāĻ¨āĻ āĻāĻŽāĻžāĻĻā§āĻ° NFT āĻāĻļāĻž āĻāĻ°āĻŋ āĻŽāĻžāĻ¨ āĻŽā§āĻ¨ā§ āĻāĻ˛ā§ .
import { NFTStorage } from 'nft.storage'; //connect to NFT.Storage Client const NFTStorageClient = new NFTStorage({ token: process.env.NEXT_PUBLIC_NFT_STORAGE_API_KEY, }); const createNFTMetadata = async ( promptInput: string, imageIPFSOrigin: string, //the ipfs path eg. ipfs://[CID] imageHTTPURL: string //an ipfs address fetchable through http for the front end to use (ie. including an ipfs http gateway on it like https://[CID].ipfs.nftstorage.link) ) => { console.log('Creating NFT Metadata...'); let nftJSON; // let's get the image data Blob from the IPFS CID that was returned from Bacalhau earlier... await getImageBlob(status, setStatus, imageHTTPURL).then( async (imageData) => { // Now let's create a unique CID for that image data - since we don't really want the rest of the data returned from the Bacalhau job.. await NFTStorageClient.storeBlob(imageData) .then((imageIPFS) => { console.log(imageIPFS); //Here's the JSON construction - only name, description and image are required fields- but I also want to save some other properties like the ipfs link and perhaps you have other properties that give your NFT's rarity to add as well nftJSON = { name: 'Bacalhau Hyperspace NFTs 2023', description: promptInput, image: imageIPFSOrigin, properties: { prompt: promptInput, type: 'stable-diffusion-image', origins: { ipfs: `ipfs://${imageIPFS}`, bacalhauipfs: imageIPFSOrigin, }, innovation: 100, content: { 'text/markdown': promptInput, }, }, }; }) .catch((err) => console.log('error creating blob cid', err)); } ); return nftJSON; };
āĻāĻāĻ¨ āĻāĻ āĻŽā§āĻāĻžāĻĄā§āĻāĻž NFT.Storage āĻ āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°āĻž āĻ¯āĻžāĻ!
await NFTStorageClient.store(nftJson) .then((metadata) => { // DONE! - do something with this returned metadata! console.log('NFT Data pinned to IPFS & stored on Filecoin!'); console.log('Metadata URI: ', metadata.url); // once saved we can use it to mint the NFT // mintNFT(metadata); }) .catch((err) => { console.log('error uploading to nft.storage'); });
Woot - āĻāĻŽāĻžāĻĻā§āĻ° āĻāĻžāĻā§ Bacalhau āĻĨā§āĻā§ āĻāĻŽāĻžāĻĻā§āĻ° āĻāĻŽā§āĻ āĻāĻā§, āĻāĻŽāĻ°āĻž NFT.Strorage-āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§ āĻāĻŽāĻžāĻĻā§āĻ° āĻŽā§āĻāĻžāĻĄā§āĻāĻž āĻ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ā§āĻ¯āĻŧ āĻāĻŦāĻ āĻ āĻŦāĻŋāĻ°āĻžāĻŽāĻāĻžāĻŦā§ āĻ¸āĻāĻ°āĻā§āĻˇāĻŖ āĻāĻ°ā§āĻāĻŋ, āĻāĻāĻ¨ āĻāĻ¸ā§āĻ¨ āĻāĻŽāĻžāĻĻā§āĻ° NFT āĻŽāĻŋāĻ¨ā§āĻ āĻāĻ°āĻŋ!
đĄ āĻĻā§āĻ°ā§āĻ¤ āĻāĻŋāĻĒ đĄNFT.Storage āĻāĻāĻžāĻĄāĻŧāĻžāĻ āĻ¸ā§āĻā§āĻ° āĻāĻžāĻ° āĻāĻŦāĻ āĻ¸ā§āĻā§āĻ° āĻĄāĻžāĻāĻ°ā§āĻā§āĻāĻ°āĻŋ āĻāĻŦāĻ āĻāĻāĻāĻŋ āĻ¸ā§āĻā§āĻ¯āĻžāĻāĻžāĻ¸() āĻĢāĻžāĻāĻļāĻ¨ā§āĻ° āĻŽāĻ¤ā§ āĻ āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ API āĻāĻ˛āĻā§āĻ˛āĻŋāĻ° āĻāĻāĻāĻŋ āĻĒāĻ°āĻŋāĻ¸āĻ°āĻ āĻ āĻĢāĻžāĻ° āĻāĻ°ā§ - āĻ¯āĻž āĻāĻāĻāĻŋ CID-āĻāĻ° IPFS āĻĒāĻŋāĻ¨āĻŋāĻ āĻāĻŦāĻ āĻĢāĻžāĻāĻ˛āĻāĻ¯āĻŧā§āĻ¨ āĻ¸ā§āĻā§āĻ°ā§āĻ āĻĄāĻŋāĻ˛ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻāĻ°ā§ -> āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻĻā§āĻ°ā§āĻĻāĻžāĻ¨ā§āĻ¤ āĻ¸āĻāĻ¯ā§āĻāĻ¨ āĻšāĻ¤ā§ āĻĒāĻžāĻ°ā§ NFT-āĻāĻ° āĻ¸ā§āĻĨāĻŋāĻ¤āĻŋ āĻĒāĻ°ā§āĻā§āĻˇāĻž āĻāĻ°āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ FEVM DApp (āĻŦāĻž FEVM āĻŽā§āĻāĻ¨āĻ¨ā§āĻ āĻ°āĻŋāĻ˛āĻŋāĻ āĻšāĻŋāĻ āĻšāĻ˛ā§ FEVM-āĻ NFT āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨)āĨ¤
āĻāĻāĻžāĻ¨ā§ 3 āĻ§āĻ°āĻ¨ā§āĻ° āĻāĻ¨ā§āĻāĻžāĻ°āĻ ā§āĻ¯āĻžāĻāĻļāĻ¨ āĻ°āĻ¯āĻŧā§āĻā§ (āĻāĻŦāĻ āĻāĻ¯āĻŧā§āĻāĻāĻŋ FEVM āĻā§āĻāĻāĻž - āĻŦāĻŋāĻāĻž āĻĒā§āĻ°āĻ¯ā§āĻā§āĻ¤āĻŋāĻ¤ā§ āĻ¸āĻŦāĻ¸āĻŽāĻ¯āĻŧ āĻāĻŋāĻā§ āĻ āĻĻā§āĻā§āĻ¤ āĻŦāĻžāĻ āĻŦā§āĻļāĻŋāĻˇā§āĻā§āĻ¯ āĻĨāĻžāĻāĻŦā§!)
āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻāĻžāĻĄāĻŧāĻžāĻ āĻā§āĻāĻ¨ āĻĨā§āĻā§ āĻĄā§āĻāĻž āĻĒā§āĻ¨āĻ°ā§āĻĻā§āĻ§āĻžāĻ° āĻāĻ°āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻĒāĻ āĻ¨āĻ¯ā§āĻā§āĻ¯ āĻāĻ˛
āĻāĻŽāĻ¨ āĻāĻ˛ āĻ˛āĻŋāĻā§āĻ¨ āĻ¯āĻžāĻ¤ā§ āĻ¸āĻžāĻāĻ¨ āĻāĻ¨ āĻāĻ°āĻ¤ā§ āĻāĻŦāĻ āĻā§āĻ¯āĻžāĻ¸ āĻĒāĻ°āĻŋāĻļā§āĻ§ āĻāĻ°āĻ¤ā§ āĻāĻāĻāĻŋ āĻāĻ¯āĻŧāĻžāĻ˛ā§āĻ āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ āĻšāĻ¯āĻŧāĨ¤ āĻ¯ā§ āĻĢāĻžāĻāĻļāĻ¨āĻā§āĻ˛āĻŋ āĻā§āĻāĻ¨ā§āĻ° āĻ āĻŦāĻ¸ā§āĻĨāĻž āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻāĻ°ā§, āĻ¯ā§āĻŽāĻ¨ NFT āĻŽāĻŋāĻ¨ā§āĻ āĻāĻ°āĻž!
āĻāĻā§āĻ¨ā§āĻ āĻļā§āĻ°ā§āĻ¤āĻž - āĻ¯āĻžāĻ°āĻž āĻā§āĻā§āĻ¤āĻŋ āĻĨā§āĻā§ āĻ¨āĻŋāĻ°ā§āĻāĻ¤ āĻāĻā§āĻ¨ā§āĻā§āĻ° āĻāĻ¨ā§āĻ¯ āĻļā§āĻ¨ā§
āĻāĻ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻĢāĻžāĻāĻļāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯, āĻāĻŽāĻ°āĻž ethers.js āĻ˛āĻžāĻāĻŦā§āĻ°ā§āĻ°āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻŦ - Ethereum API-āĻāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻšāĻžāĻ˛āĻāĻž āĻŽā§āĻĄāĻŧāĻ, āĻāĻŽāĻžāĻĻā§āĻ° āĻā§āĻā§āĻ¤āĻŋāĻ° āĻ¸āĻžāĻĨā§ āĻ¸āĻāĻ¯ā§āĻ āĻāĻ°āĻ¤ā§ āĻāĻŦāĻ āĻāĻ¤ā§ āĻāĻ˛ āĻāĻ°āĻ¤ā§āĨ¤
āĻāĻāĻāĻŋ āĻĒāĻžāĻŦāĻ˛āĻŋāĻ RPC āĻāĻ° āĻ¸āĻžāĻĨā§ āĻ°āĻŋāĻĄ āĻŽā§āĻĄā§ āĻā§āĻā§āĻ¤āĻŋāĻ° āĻ¸āĻžāĻĨā§ āĻ¸āĻāĻ¯ā§āĻā§āĻ¤ āĻšāĻā§āĻā§:
//The compiled contract found in pages/api/hardhat/artifacts/contracts import BacalhauCompiledContract from '@Contracts/BacalhauFRC721.sol/BacalhauFRC721.json'; //On-chain address of the contract const contractAddressHyperspace = '0x773d8856dd7F78857490e5Eea65111D8d466A646'; //A public RPC Endpoint (see table from contract section) const rpc = 'https://api.hyperspace.node.glif.io/rpc/v1'; const provider = new ethers.providers.JsonRpcProvider(rpc); const connectedReadBacalhauContract = new ethers.Contract( contractAddressHyperspace, BacalhauCompiledContract.abi, provider );
āĻā§āĻā§āĻ¤āĻŋāĻ¤ā§ āĻāĻā§āĻ¨ā§āĻā§āĻ° āĻāĻ¨ā§āĻ¯ āĻļā§āĻ¨āĻž. āĻ¯ā§āĻšā§āĻ¤ā§ āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻĒāĻ āĻ¨āĻ¯ā§āĻā§āĻ¯ (āĻĒāĻžāĻāĻ¯āĻŧāĻž) āĻāĻā§āĻ¨ā§āĻ, āĻ¤āĻžāĻ āĻāĻŽāĻ°āĻž āĻ āĻ¨-āĻā§āĻāĻ¨ āĻāĻā§āĻ¨ā§āĻ āĻ¨āĻŋāĻ°ā§āĻāĻŽāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻļā§āĻ¨āĻ¤ā§ āĻĒāĻžāĻŦāĻ˛āĻŋāĻ RPC āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°āĻŋāĨ¤
//use the read-only connected Bacalhau Contract connectedReadBacalhauContract.on( // Listen for the specific event we made in our contract 'NewBacalhauFRC721NFTMinted', (sender: string, tokenId: number, tokenURI: string) => { //DO STUFF WHEN AN EVENT COMES IN // eg. re-fetch NFT's, store in state and change page status } );
āĻ˛ā§āĻāĻžāĻ° āĻŽā§āĻĄā§ āĻā§āĻā§āĻ¤āĻŋāĻ° āĻ¸āĻžāĻĨā§ āĻ¸āĻāĻ¯ā§āĻ āĻāĻ°āĻž - āĻāĻ° āĻāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ āĻ¯ā§ Ethereum āĻŦāĻ¸ā§āĻ¤ā§āĻāĻŋ āĻāĻāĻāĻŋ āĻāĻ¯āĻŧāĻžāĻ˛ā§āĻ āĻĻā§āĻŦāĻžāĻ°āĻž āĻāĻ¯āĻŧā§āĻŦ āĻŦā§āĻ°āĻžāĻāĻāĻžāĻ°ā§ āĻāĻ¨āĻā§āĻāĻļāĻ¨ āĻāĻ°āĻž āĻšāĻā§āĻā§ āĻ¯āĻžāĻ¤ā§ āĻāĻāĻāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻāĻžāĻ°ā§ āĻāĻāĻāĻŋ āĻ˛ā§āĻ¨āĻĻā§āĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻ¸āĻžāĻāĻ¨ āĻāĻ¨ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§ āĻāĻŦāĻ āĻā§āĻ¯āĻžāĻ¸ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻ āĻ°ā§āĻĨ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§ - āĻāĻ āĻāĻžāĻ°āĻŖā§āĻ āĻāĻŽāĻ°āĻž āĻāĻāĻāĻŋ window.ethereum āĻĒāĻ°ā§āĻā§āĻˇāĻž āĻāĻ°āĻāĻŋ āĻŦāĻ¸ā§āĻ¤ā§
//Typescript needs to know window is an object with potentially and ethereum value. There might be a better way to do this? Open to tips! declare let window: any; //The compiled contract found in pages/api/hardhat/artifacts/contracts import BacalhauCompiledContract from '@Contracts/BacalhauFRC721.sol/BacalhauFRC721.json'; //On-chain address of the contract const contractAddressHyperspace = '0x773d8856dd7F78857490e5Eea65111D8d466A646'; //check for the ethereum object if (!window.ethereum) { //ask user to install a wallet or connect //abort this } // else there's a wallet provider else { // same function - different provider - this one has a signer - the user's connected wallet address const provider = new ethers.providers.Web3Provider(window.ethereum); const contract = new ethers.Contract( contractAddressHyperspace, BacalhauCompiledContract.abi, provider ); const signer = provider.getSigner(); const connectedWriteBacalhauContract = contract.connect(signer); }
āĻ˛āĻŋāĻā§āĻ¨ āĻ¸āĻāĻ¯ā§āĻā§āĻ¤ āĻā§āĻā§āĻ¤āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°ā§ āĻŽāĻŋāĻ¨ā§āĻ āĻĢāĻžāĻāĻļāĻ¨ āĻāĻ˛ āĻāĻ°āĻž.
āĻĒā§āĻ°āĻĨāĻŽāĻ¤, āĻ¨āĻŋāĻļā§āĻāĻŋāĻ¤ āĻāĻ°ā§āĻ¨ āĻ¯ā§ āĻāĻŽāĻžāĻĻā§āĻ° āĻāĻžāĻā§ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻāĻžāĻ°ā§āĻ° āĻāĻžāĻ āĻĨā§āĻā§ āĻāĻāĻāĻŋ āĻāĻ¯āĻŧāĻžāĻ˛ā§āĻ āĻ āĻŋāĻāĻžāĻ¨āĻž āĻāĻā§ āĻāĻŦāĻ āĻāĻŽāĻ°āĻž FVM āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ āĻā§āĻāĻ¨ā§ āĻāĻāĻŋāĨ¤ āĻāĻāĻžāĻ¨ā§ āĻāĻ¯āĻŧā§āĻāĻāĻŋ āĻ¸āĻšāĻžāĻ¯āĻŧāĻ āĻāĻ¯āĻŧāĻžāĻ˛ā§āĻ āĻĢāĻžāĻāĻļāĻ¨ āĻ°āĻ¯āĻŧā§āĻā§ āĻ¯āĻž āĻāĻĒāĻ¨āĻŋ āĻāĻžāĻāĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨, āĻ¯āĻžāĻ° āĻŽāĻ§ā§āĻ¯ā§ āĻ°āĻ¯āĻŧā§āĻā§ āĻā§āĻāĻžāĻŦā§ āĻā§āĻāĻ¨āĻāĻāĻĄāĻŋ āĻā§āĻ āĻāĻ°āĻŦā§āĻ¨ āĻāĻŦāĻ āĻā§āĻāĻžāĻŦā§ āĻĒā§āĻ°ā§āĻā§āĻ°āĻžāĻŽā§āĻ¯āĻžāĻāĻŋāĻāĻāĻžāĻŦā§ āĻŽā§āĻāĻžāĻŽāĻžāĻ¸ā§āĻ/āĻāĻ¯āĻŧāĻžāĻ˛ā§āĻā§ āĻšāĻžāĻāĻĒāĻžāĻ°āĻ¸ā§āĻĒā§āĻ¸ āĻ¨ā§āĻāĻāĻ¯āĻŧāĻžāĻ°ā§āĻ āĻ¯ā§āĻā§āĻ¤ āĻāĻ°āĻŦā§āĻ¨āĨ¤ āĻāĻĒāĻ¨āĻŋ āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ āĻāĻĨā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻŽ āĻ āĻŦāĻā§āĻā§āĻ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°ā§ āĻŦāĻž ethers.js āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°ā§ āĻāĻ¯āĻŧāĻžāĻ˛ā§āĻā§āĻ° āĻ¸āĻžāĻĨā§ āĻ¯ā§āĻāĻžāĻ¯ā§āĻ āĻāĻ°āĻ¤ā§ āĻĒāĻžāĻ°ā§āĻ¨āĨ¤
declare let window: any; const fetchWalletAccounts = async () => { console.log('Fetching wallet accounts...'); await window.ethereum //use ethers? .request({ method: 'eth_requestAccounts' }) .then((accounts: string[]) => { return accounts; }) .catch((error: any) => { if (error.code === 4001) { // EIP-1193 userRejectedRequest error console.log('Please connect to MetaMask.'); } else { console.error(error); } }); }; const fetchChainId = async () => { console.log('Fetching chainId...'); await window.ethereum .request({ method: 'eth_chainId' }) .then((chainId: string[]) => { return chainId; }) .catch((error: any) => { if (error.code === 4001) { // EIP-1193 userRejectedRequest error console.log('Please connect to MetaMask.'); } else { console.error(error); } }); }; //!! This function checks for a wallet connection WITHOUT being intrusive to to the user or opening their wallet export const checkForWalletConnection = async () => { if (window.ethereum) { console.log('Checking for Wallet Connection...'); await window.ethereum .request({ method: 'eth_accounts' }) .then(async (accounts: String[]) => { console.log('Connected to wallet...'); // Found a user wallet return true; }) .catch((err: Error) => { console.log('Error fetching wallet', err); return false; }); } else { //Handle no wallet connection return false; } }; //Subscribe to changes on a user's wallet export const setWalletListeners = () => { console.log('Setting up wallet event listeners...'); if (window.ethereum) { // subscribe to provider events compatible with EIP-1193 standard. window.ethereum.on('accountsChanged', (accounts: any) => { //logic to check if disconnected accounts[] is empty if (accounts.length < 1) { //handle the locked wallet case } if (userWallet.accounts[0] !== accounts[0]) { //user has changed address } }); // Subscribe to chainId change window.ethereum.on('chainChanged', () => { // handle changed chain case }); } else { //handle the no wallet case } }; export const changeWalletChain = async (newChainId: string) => { console.log('Changing wallet chain...'); const provider = window.ethereum; try { await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: newChainId }], //newChainId }); } catch (error: any) { alert(error.message); } }; //AddHyperspaceChain export const addHyperspaceNetwork = async () => { console.log('Adding the Hyperspace Network to Wallet...'); if (window.ethereum) { window.ethereum .request({ method: 'wallet_addEthereumChain', params: [ { chainId: '0xc45', rpcUrls: [ 'https://hyperspace.filfox.info/rpc/v0', 'https://filecoin-hyperspace.chainstacklabs.com/rpc/v0', ], chainName: 'Filecoin Hyperspace', nativeCurrency: { name: 'tFIL', symbol: 'tFIL', decimals: 18, }, blockExplorerUrls: [ 'https://fvm.starboard.ventures/contracts/', 'https://hyperspace.filscan.io/', 'https://beryx.zondax.chfor', ], }, ], }) .then((res: XMLHttpRequestResponseType) => { console.log('added hyperspace successfully', res); }) .catch((err: ErrorEvent) => { console.log('Error adding hyperspace network', err); }); } };
āĻ˛āĻŋāĻāĻŋāĻ¤ āĻŽā§āĻĄā§ āĻā§āĻā§āĻ¤āĻŋ āĻŽāĻŋāĻ¨ā§āĻ āĻĢāĻžāĻāĻļāĻ¨ āĻāĻ˛ āĻāĻ°ā§āĻ¨....
// Pass in the metadata return from saving to NFT.Storage const mintNFT = async (metadata: any) => { await connectedWriteBacalhauContract // The name of our function in our smart contract .mintBacalhauNFT( userWallet.accounts[0], //users account to use metadata.url //test ipfs address ) .then(async (data: any) => { console.log('CALLED CONTRACT MINT FUNCTION', data); await data .wait() .then(async (tx: any) => { console.log('tx', tx); //CURRENTLY NOT RETURNING TX - (I use event triggering to know when this function is complete) let tokenId = tx.events[1].args.tokenId.toString(); console.log('tokenId args', tokenId); setStatus({ ...INITIAL_TRANSACTION_STATE, success: successMintingNFTmsg(data), }); }) .catch((err: any) => { console.log('ERROR', err); setStatus({ ...status, loading: '', error: errorMsg(err.message, 'Error minting NFT'), }); }); }) .catch((err: any) => { console.log('ERROR1', err); setStatus({ ...status, loading: '', error: errorMsg( err && err.message ? err.message : null, 'Error minting NFT' ), }); }); }
āĻāĻ - āĻāĻ¨āĻāĻĢāĻāĻŋ āĻŽāĻŋāĻ¨ā§āĻā§āĻĄ!! āĻāĻāĻ¨āĻŋāĻāĻ°ā§āĻ¨ āĻĄāĻžāĻ¨ā§āĻ¸ āĻŽā§āĻĄ āĻ¸āĻŽāĻ¯āĻŧ!
Bacalhau āĻĄā§āĻāĻžāĻ° āĻāĻĒāĻ° āĻĒā§āĻ¨āĻ°āĻžāĻŦā§āĻ¤ā§āĻ¤āĻŋāĻŽā§āĻ˛āĻ, āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻ āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻāĻ°āĻŖā§āĻ° āĻāĻžāĻāĻā§āĻ˛āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨ āĻāĻ°āĻ¤ā§ āĻ¨āĻŋāĻā§āĻā§ āĻāĻžāĻ˛āĻāĻžāĻŦā§ āĻ§āĻžāĻ° āĻĻā§āĻ¯āĻŧāĨ¤
ETL āĻĒā§āĻ°āĻ¸ā§āĻ¸
āĻŽā§āĻļāĻŋāĻ¨ āĻ˛āĻžāĻ°ā§āĻ¨āĻŋāĻ āĻāĻŦāĻ āĻāĻāĻ
āĻāĻāĻāĻāĻŋ āĻĄā§āĻāĻž āĻāĻ¨ā§āĻāĻŋāĻā§āĻ°ā§āĻļāĻ¨
āĻāĻ¨ā§āĻ¯ āĻ¸āĻš āĻŦā§āĻ¯āĻžāĻ āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻāĻ°āĻŖ
āĻāĻŋāĻĄāĻŋāĻ āĻāĻŦāĻ āĻāĻŋāĻ¤ā§āĻ° āĻĒā§āĻ°āĻā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻāĻ°āĻŖ - āĻ¸ā§āĻāĻ¨āĻļā§āĻ˛āĻĻā§āĻ° āĻāĻ¨ā§āĻ¯ āĻĻā§āĻ°ā§āĻĻāĻžāĻ¨ā§āĻ¤
Bacalhau āĻĄāĻā§āĻ¸ā§ āĻāĻāĻžāĻ§āĻŋāĻ āĻāĻĻāĻžāĻšāĻ°āĻŖ āĻāĻā§ āĻāĻŋāĻāĻžāĻŦā§ āĻāĻĒāĻ°ā§āĻ° āĻāĻŋāĻā§ āĻ āĻ°ā§āĻāĻ¨ āĻāĻ°āĻž āĻ¯āĻžāĻ¯āĻŧāĨ¤
āĻ¯āĻāĻ¨ Bacalhau FEVM āĻ¸ā§āĻŽāĻžāĻ°ā§āĻ āĻā§āĻā§āĻ¤āĻŋāĻā§āĻ˛āĻŋ āĻĨā§āĻā§ Bacalhau āĻā§ āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ āĻāĻ˛ āĻāĻ°āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻāĻ¨ā§āĻāĻŋāĻā§āĻ°ā§āĻļāĻ¨ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻ¤ā§ āĻŦā§āĻ¯āĻ¸ā§āĻ¤, āĻāĻāĻžāĻ¨ā§ Bacalhau x FVM āĻ¸āĻšāĻ¯ā§āĻāĻŋāĻ¤āĻžāĻ° āĻŦāĻŋāĻˇāĻ¯āĻŧā§ āĻāĻŋāĻā§ āĻāĻŋāĻ¨ā§āĻ¤āĻžāĻāĻžāĻŦāĻ¨āĻž āĻ°āĻ¯āĻŧā§āĻā§:
āĻāĻŽāĻ°āĻž āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ā§ āĻāĻĒāĻ¨āĻžāĻ° āĻ¸ā§āĻŽāĻžāĻ°ā§āĻ āĻā§āĻā§āĻ¤āĻŋ āĻĨā§āĻā§ āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ Bacalhau āĻāĻžāĻ˛āĻžāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻāĻĒāĻžāĻ¯āĻŧ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻāĻŋ!!!! āĻāĻ āĻĒā§āĻ°āĻāĻ˛ā§āĻĒāĻāĻŋāĻā§ āĻŦāĻ˛āĻž āĻšāĻ¯āĻŧ āĻĒā§āĻ°āĻā§āĻā§āĻ āĻĢā§āĻ°āĻ/āĻĒā§āĻ°āĻā§āĻā§āĻ āĻ˛āĻŋāĻ˛āĻŋāĻĒā§āĻ¯āĻžāĻĄ - āĻāĻŦāĻ āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻāĻ¨ā§āĻāĻŋāĻā§āĻ°ā§āĻļāĻ¨ āĻ˛ā§āĻ¯āĻŧāĻžāĻ° āĻšāĻŦā§ āĻ¯āĻž FEVM āĻ¸ā§āĻŽāĻžāĻ°ā§āĻ āĻāĻ¨ā§āĻā§āĻ°āĻžāĻā§āĻ āĻĨā§āĻā§ Bacalhau āĻāĻŦ āĻāĻ˛ āĻāĻ°āĻ¤ā§ āĻ¸āĻā§āĻˇāĻŽ āĻāĻ°āĻŦā§āĨ¤
āĻāĻŽāĻžāĻĻā§āĻ° āĻ¨āĻŋāĻāĻāĻ˛ā§āĻāĻžāĻ°ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻ¸āĻžāĻāĻ¨ āĻāĻĒ āĻāĻ°ā§ āĻŦāĻž āĻ¨ā§āĻā§āĻ° āĻ¸āĻžāĻŽāĻžāĻāĻŋāĻāĻā§āĻ˛āĻŋāĻ¤ā§ āĻ¯ā§āĻāĻĻāĻžāĻ¨ āĻāĻ°ā§ āĻāĻ° āĻ āĻā§āĻ°āĻāĻ¤āĻŋāĻ° āĻāĻĒāĻ° āĻ¨āĻāĻ° āĻ°āĻžāĻā§āĻ¨āĨ¤
āĻ āĻāĻŋāĻ¨āĻ¨ā§āĻĻāĻ¨ āĻ¯āĻĻāĻŋ āĻāĻĒāĻ¨āĻŋ āĻĒā§āĻ°ā§ āĻĒāĻĨ āĻĒāĻĄāĻŧā§āĻ¨!!!
āĻāĻŽāĻŋ āĻāĻāĻāĻŋ āĻ˛āĻžāĻāĻ, āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯, āĻ āĻ¨ā§āĻ¸āĻ°āĻŖ āĻŦāĻž āĻļā§āĻ¯āĻŧāĻžāĻ° āĻā§āĻ¤āĻā§āĻ āĻ¯āĻĻāĻŋ āĻāĻāĻŋ āĻāĻĒāĻ¨āĻžāĻ° āĻāĻ¨ā§āĻ¯ āĻĻāĻ°āĻāĻžāĻ°ā§ āĻāĻŋāĻ˛! <3
Bacalhau āĻ¸āĻžāĻĨā§ āĻ¯ā§āĻāĻžāĻ¯ā§āĻ āĻ°āĻžāĻā§āĻ¨!
âĨī¸ āĻĄā§āĻā§āĻ˛āĻĒāĻžāĻ°āĻ ā§āĻ¯āĻžāĻ˛āĻŋāĻ° āĻ¸āĻžāĻĨā§
āĻāĻāĻāĻ¨ āĻ¸ā§āĻĒāĻ¨āĻ¸āĻ° āĻšāĻ¯āĻŧā§ āĻ ā§āĻ¯āĻžāĻ˛āĻŋāĻ¸āĻ¨ āĻšā§āĻ¯āĻŧāĻžāĻ°āĻā§ āĻ¸āĻŽāĻ°ā§āĻĨāĻ¨ āĻāĻ°ā§āĻ¨āĨ¤ āĻā§āĻ¨ āĻĒāĻ°āĻŋāĻŽāĻžāĻŖ āĻĒā§āĻ°āĻļāĻāĻ¸āĻž āĻāĻ°āĻž āĻšāĻ¯āĻŧ!
āĻšā§āĻ¯āĻžāĻļāĻ¨ā§āĻĄ āĻ¸ā§āĻĒāĻ¨āĻ¸āĻ° āĻ¸āĻŽā§āĻĒāĻ°ā§āĻā§ āĻāĻ°āĻ āĻāĻžāĻ¨ā§āĻ¨
āĻāĻāĻžāĻĄāĻŧāĻžāĻ āĻāĻāĻžāĻ¨ā§ āĻĒā§āĻ°āĻāĻžāĻļāĻŋāĻ¤.