Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Polygon support #57

Merged
merged 3 commits into from
Mar 18, 2022
Merged

Adding Polygon support #57

merged 3 commits into from
Mar 18, 2022

Conversation

Jonas-Lieske
Copy link
Contributor

Here is my solution on how to implement Polygon support as discussed in #21.

Requirements
The hardhat-etherscan package needs to be updated to version 3.0.0 since it offers a new feature to configure multiple API keys for scans at once. The doc entry is HERE. I haven't noticed any problems with the update.

Improvements that could be made
I do not have any experience with REACT so I didn't try to change anything on the code base. It still says ETH for the pricing and the polygon chain is not being recognized as a main chain.
I also needed to use the gasMultiplier for polygon chain since there have been problems with the deployment and verification, because of a too low gas fee. AFAIK this is a problem with the calculation of gas fee by hardhat.

I tested it and it worked, however I only recently got into the field of smart contracts so I would appreciate any feedback!

@liarco
Copy link
Member

liarco commented Mar 3, 2022

Hi @Jonas-Lieske, thank you very much for this contribution, I'm gonna review this PR as soon as possible.

Would you mind if I make some changes (if needed) or implement the missing stuff for the DAPP? And also, would you be willing to test the final result so we can make sure everything is fine before merging?

Thank you.

@Jonas-Lieske
Copy link
Contributor Author

Hi @Jonas-Lieske, thank you very much for this contribution, I'm gonna review this PR as soon as possible.

Would you mind if I make some changes (if needed) or implement the missing stuff for the DAPP? And also, would you be willing to test the final result so we can make sure everything is fine before merging?

Thank you.

Do as many changes as needed 😁
I can also run the tests at the end, no problem.

@tab00
Copy link

tab00 commented Mar 3, 2022

Did you also do the things described in https://docs.opensea.io/docs/polygon-basic-integration ?

@liarco
Copy link
Member

liarco commented Mar 3, 2022

@tab00 we don't agree with the first suggestion provided by OpenSea ("Overriding isApprovedForAll() to reduce trading friction"). The hard-coded approval of the OpenSea marketplace is something that we don't want to implement by default in our contracts since we see it as a bad-practice from a security point of view.

That said, I need to do some research about the rest of the article. 😉

@tab00
Copy link

tab00 commented Mar 3, 2022

we don't agree with the first suggestion provided by OpenSea ("Overriding isApprovedForAll() to reduce trading friction")

Yes, I had come across some discussion recently about the risks of that in https://gist.github.com/483eb43bc6ed30b14f01e01842e3339b#gistcomment-4073311

@liarco
Copy link
Member

liarco commented Mar 5, 2022

Hi @Jonas-Lieske it seems like I made a mistake while trying to rebase your fork on the latest version and now I have no access to your repository.

Would you please apply the following patch as a new commit and push it to your branch?

commit c0da904673c48a72bff04eed6cab38fadff13a85
Author: Marco Lipparini <[email protected]>
Date:   Sat Mar 5 20:35:11 2022 +0100

    Added Polygon support

diff --git a/smart-contract/hardhat.config.ts b/smart-contract/hardhat.config.ts
index 0007696..4b4fe0b 100644
--- a/smart-contract/hardhat.config.ts
+++ b/smart-contract/hardhat.config.ts
@@ -112,6 +112,10 @@ const config: HardhatUserConfig = {
       // Ethereum
       rinkeby: process.env.BLOCK_EXPLORER_API_KEY,
       mainnet: process.env.BLOCK_EXPLORER_API_KEY,
+
+      // Polygon
+      polygon: process.env.BLOCK_EXPLORER_API_KEY,
+      polygonMumbai: process.env.BLOCK_EXPLORER_API_KEY,
     },
   },
 };
diff --git a/smart-contract/lib/Networks.ts b/smart-contract/lib/Networks.ts
index 687a252..d217c12 100644
--- a/smart-contract/lib/Networks.ts
+++ b/smart-contract/lib/Networks.ts
@@ -3,7 +3,7 @@ import NetworkConfigInterface from './NetworkConfigInterface';
 export const ethereumTestnet: NetworkConfigInterface = {
   chainId: 4,
   blockExplorer:{
-    name: 'Etherscan',
+    name: 'Etherscan (Rinkeby)',
     generateContractUrl: (contractAddress: string) => `https://rinkeby.etherscan.io/address/${contractAddress}`,
   },
 }
@@ -15,3 +15,19 @@ export const ethereumMainnet: NetworkConfigInterface = {
     generateContractUrl: (contractAddress: string) => `https://etherscan.io/address/${contractAddress}`,
   },
 }
+
+export const polygonTestnet: NetworkConfigInterface = {
+  chainId: 80001,
+  blockExplorer:{
+    name: 'Polygonscan (Mumbai)',
+    generateContractUrl: (contractAddress: string) => `https://mumbai.polygonscan.com/address/${contractAddress}`,
+  },
+}
+
+export const polygonMainnet: NetworkConfigInterface = {
+  chainId: 137,
+  blockExplorer: {
+    name: 'Polygonscan',
+    generateContractUrl: (contractAddress: string) => `https://polygonscan.com/address/${contractAddress}`,
+  },
+}

If you save it to a polygon.patch file you should be able to apply it with git apply polygon.patch. Then I should be able to re-open this PR.

My changes in version 2.0.0 are based on your original idea and this patch should enable support for Polygon network.
You should then be able to test it by updating the imports in the configuration file:

import { ethereumTestnet, ethereumMainnet } from '../lib/Networks';

And referencing the Polygon networks here:
testnet: ethereumTestnet,
mainnet: ethereumMainnet,

The env variables are now generic so there is no need to add new ones, you can simply use the default ones.

Let me know if you can help me with this, thank you very much! 🙏

@Jonas-Lieske
Copy link
Contributor Author

Hey @liarco, I've applied and pushed the changes you mentioned, ran the tests and also did some manual testing.
The only thing that I noticed is that the currency being displayed on the minting page is still ETH, the rest is working fine 🙂

@liarco liarco reopened this Mar 6, 2022
@liarco
Copy link
Member

liarco commented Mar 6, 2022

Thank you very much @Jonas-Lieske, I really appreciate it.

You are right I have to make it customizable as well. 😉 I see you also mentioned you had to use the "gasMultiplier for polygon chain", is this still relevant? Would you please elaborate on this so I can understand if we need to take it into consideration too?

@Jonas-Lieske
Copy link
Contributor Author

No problem @liarco, I gotta thank you for this awesome repo 😉

Interestingly enough, the problem I mentioned where the gasMultiplier was needed is not occurring anymore 🤔

When I tested my implementation, an error message told me that the gas fees were set too low to deploy the contract.
I researched about it and found out that the gas fees were miscalculated by hardhat.
To fix this I set the gasMultiplier in the hardhat config to 1.1, meaning it would set them 10% higher than estimated.
I'm glad that this issue is fixed 😁

@liarco
Copy link
Member

liarco commented Mar 6, 2022

@Jonas-Lieske 🙏

I'm happy to hear this might be fixed. Infura (which is also used by MetaMask) had a lot of issue in the past days so I have seen many people complaining about failing transactions, wrong gas estimations, etc. I hope it was the culprit.

I committed the support for custom token symbols, I also decided to append an explicit (test) suffix (e.g. ETH (test)) for testing networks.

Now I think we should take care of the optimizations suggested by OpenSea. I need to understand the purpose of each of them and I would like to limit the changes to what is absolutely required.

@Juan34-crypto
Copy link

You guys are the best !! I just want to now if the code is ready to use for polygon, or i need to wait for another tutorial to start my smart contract , i been trying everything and I see you guys are so close to get this code ready

@liarco
Copy link
Member

liarco commented Mar 7, 2022

Hi @Juan34-crypto, it's not ready for production but if you could test it and give us feedback that would be appreciated.

You can clone the git repo from this PR or you can download it as a ZIP file.

Then you should be able to follow my instructions from the previous message:

...
My changes in version 2.0.0 are based on your original idea and this patch should enable support for Polygon network. You should then be able to test it by updating the imports in the configuration file:

import { ethereumTestnet, ethereumMainnet } from '../lib/Networks';

And referencing the Polygon networks here:

testnet: ethereumTestnet,
mainnet: ethereumMainnet,

The env variables are now generic so there is no need to add new ones, you can simply use the default ones.

I still need to know if the project works as expected on OpenSea or if it requires some specific changes in order to support the Polygon chain correctly.

Thank you.

@Jonas-Lieske
Copy link
Contributor Author

I'm happy to hear this might be fixed. Infura (which is also used by MetaMask) had a lot of issue in the past days so I have seen many people complaining about failing transactions, wrong gas estimations, etc. I hope it was the culprit.

Yes, that could be the reason 🙂

I still need to know if the project works as expected on OpenSea or if it requires some specific changes in order to support the Polygon chain correctly.

I have tested it on OpenSea and didn't encounter any error.

Now I think we should take care of the optimizations suggested by OpenSea. I need to understand the purpose of each of them and I would like to limit the changes to what is absolutely required.

From what I can see the meta transactions would be a nice addition, not only for Polygon but also for Ethereum.
However, I haven't seen any comparable implementation on another marketplace, which might mean that this is only useful for OpenSea (or maybe I just missed an article 🤷‍♂️).
What do you think @liarco?

@liarco
Copy link
Member

liarco commented Mar 7, 2022

Thank you @Jonas-Lieske, I took a look at the docs from OpenSea and I found a reference to this at the bottom: https://docs.openzeppelin.com/learn/sending-gasless-transactions

But there you find a warning at the top, saying:

This guide is now deprecated, as it uses GSNv1, which is no longer supported. Consider using Defender for setting up your own meta-transaction relayers instead, or using GSNv2 from the OpenGSN team for a decentralized solution.

To me it's not clear if this method can still be considered a best-practice or if we should avoid it... I'm gonna do some more research! 😉

@nftkk
Copy link

nftkk commented Mar 8, 2022

Here is my solution on how to implement Polygon support as discussed in #21.

Requirements The hardhat-etherscan package needs to be updated to version 3.0.0 since it offers a new feature to configure multiple API keys for scans at once. The doc entry is HERE. I haven't noticed any problems with the update.

Improvements that could be made I do not have any experience with REACT so I didn't try to change anything on the code base. It still says ETH for the pricing and the polygon chain is not being recognized as a main chain. I also needed to use the gasMultiplier for polygon chain since there have been problems with the deployment and verification, because of a too low gas fee. AFAIK this is a problem with the calculation of gas fee by hardhat.

I tested it and it worked, however I only recently got into the field of smart contracts so I would appreciate any feedback!

Hello @Jonas-Lieske
thanks for your tread. i saw you are from germany as well :) maybe you help me to fix the issue with gas problems on the dapp? liarco guided me to this tread.

here was my issue on closed tread: #96 (comment)

@liarco
Copy link
Member

liarco commented Mar 8, 2022

@nftkk I'm sorry to say this but this is not what I actually meant. Here we are working on the implementation for the new feature, it's not a help-desk for personal support.

You are more than welcome to:

  1. Download the code from the branch @Jonas-Lieske shared here (which features a testing implementation for Polygon)
  2. Leave feedback here about what's working and what's not by providing with as much information as possible

If you can do this, then I will much appreciate it, but in the issue you linked above you are using a wrong version so we cannot help you with that.

@nftkk
Copy link

nftkk commented Mar 8, 2022

@liarco
sorry i forget to share the information that i did transfer the lines from @Jonas-Lieske like he does already. so i meet the requirement for feedback? Sorry i really dont want to post useless stuff here.

@liarco
Copy link
Member

liarco commented Mar 8, 2022

@liarco sorry i forget to share the information that i did transfer the lines from @Jonas-Lieske like he does already. so i meet the requirement for feedback? Sorry i really dont want to post useless stuff here.

Ok no problem, but please, since copying changes manually can lead to errors, I ask you to start from a clean copy of the new code and test it as a brand new project. You should then report what you are doing and what's happening.

Thank you for your time.

@granthughes1999
Copy link

granthughes1999 commented Mar 9, 2022

Hello,

I used the link in your reply above that says "the new code" and downloaded that zip file (nft-erc721-collection-main). After successfully deploying on polygon, verifying the contract, yarn build the minting-dapp, deploying the minting-dapp on a static host and finally opening the whitelist, I am met with the an error on the minting-dapp page that says Error Unsupported Network. This occurs when i connect my metamask to polygon, which is where the contract was deployed and successfully verified on polyscan. The only step i can see causing this issue was when you add in your ContractAddress to CollectionConfig.js before verifying. I added the ContractAddress and set it as a string but i forgot to save the file before verifying the contract. do you think this miss-step could cause that issue?

if i connect my metmask to rinkeby while on the minting-dapp, a get this "Could not find the contract, are you connected to the right chain?". just for more insight.

thanks for everything!!

@liarco
Copy link
Member

liarco commented Mar 9, 2022

Hi @granthughes1999, thank you for your detailed information. 🙏
I think you are missing the configuration explained here: #57 (comment)

You should tell the system that you are using polygon networks instead of the ethereum one. Let me know if it's clear enough! 😉

Thank you

@liarco
Copy link
Member

liarco commented Mar 11, 2022

@Juan34-crypto please calm down. This is not something you should take this way. It took me months (after 23 years studying/working as a developer) in order to get here, you should take your time nobody can speed it up for you here. It's all up to you.

Your error is a connection error, you should check your configuration, maybe start over and follow every step really carefully.

This is also an unstable version of this software, you are not supposed to launch a real project with this, so I don't see any reason to rush. We need to get this done right, not fast.
If you need this to be "fast", then there are plenty of developers out there that can be hired for this. 😉

@nftkk
Copy link

nftkk commented Mar 11, 2022

@liarco
thanks for your help. i try my best to give you and the community best feedback as its possible for me.

now i its a bit funny. i start my terminal an run whiteliste open by the .env with private keys. today it works perfect. i didnt change anything. maybe yesterday the blockhain was busy and the gas fees higher. it seems that infura cant handle this. now it is the clean code of @Jonas-Lieske

by the way it works now on both ways. direct by .env and truffle.

after that i rund the dev-server and connect a wallet wich was on white list and try to mint. i get the same error as before. so there was no faults on my code before.

image

At this point it must have something to do with DAPP and the configuration. I wonder why a gas fee is pre-calculated at this point, but from here on out it has to run normally via meta mask. Or have I thought incorrectly about that?

i did research a bit and red something about (it was eth, but in this case i think it doesnt matter):
Insufficient balance for transaction
When you put a high gasPrice, for example 100 gwei and you don't have sufficient ETH in your wallet then you may get this error. Also if you are passing high gasLimit value, it requires that you have enough ETH balance.

Maybe the reason is my minting price? i want to set 100 matic, so i set it too 100.0 . I'm a bit confused though. on opensea you select the polygon block chain, but i have not seen any projects that trade with matic, but always with wrapped eth via the polygon chain. so my price would be wrong, that would be 100 eth lol. So do you always have to specify eth? if so, you would have to revise the code again so that no matic is displayed as currency.

EDIT: i see on the video now it is relevant if you sell on opeansea, but in our case we dont sell it on opensea, we sell it on our own minting page. so the setting should be finde. we just have an gas issue here. but still have the question how will opeansea show the floor price if we mint on matic? opeansea only support wrapped eth or other currency on polygon but not direct matic. this is very important for collection. it would be very bad if opensea will show a floor price of 0 because matic is not supported.

here is a video https://www.youtube.com/watch?v=tDsllLMLKWM

price: 100.00,

image

@nftkk
Copy link

nftkk commented Mar 11, 2022

update:
i was sooo stupid. this error comes if you have not enough matic on the wallet.... sorry guys. everything works perfect!!!!

just the one question is very interesting. how will opensea handle the floorprice if we sell on matic wich is not supported on opensea?

@nftkk
Copy link

nftkk commented Mar 11, 2022

thanks for support! we are working on a different layout from the minting dapp. i will share if it is done next week.

just bought an ape from you to support you guys!!!!

image

@liarco
Copy link
Member

liarco commented Mar 12, 2022

update: i was sooo stupid. this error comes if you have not enough matic on the wallet.... sorry guys. everything works perfect!!!!

You were not stupid at all. We try to make this stuff accessible to a lot of people, but it's not easy to understand how everything works and all the things that can go wrong. It takes time and a lot of trial and error. Take your time, you will improve with time, like all of us.

just the one question is very interesting. how will opensea handle the floorprice if we sell on matic wich is not supported on opensea?

You should check this out on the test version of OpenSea.

@nftkk
Copy link

nftkk commented Mar 12, 2022

I have now run a full test on the Mumbai Network.

There are 2 important points that are missing.

  1. rarity of properties in %. It says "new traid" instead of the %
  2. no floor price
  3. volume traded

i think this is very important for an collection. of course the target is to sell out on minting dapp but is is very important to show up an floor price for it. how was that on eth chain? is there a floor price?

how can i add the % rarrity of the properties?

@liarco
Copy link
Member

liarco commented Mar 12, 2022

@nftkk would you mind sharing the links so we can check it out? The first point should have nothing to do with this project, it might be just a "cache" issue (many ethereum collections on mainnet show the same thing at the beginning). I have no clue about floor price and volume.

@nftkk
Copy link

nftkk commented Mar 12, 2022

I did some research. the floor price and the trading volume only get tracked if you list directly on opensea, without own smart contract. i think i will run it on this way.

there are 2 ways:

  1. to do it with an smart contract
  2. directly on opensea like this guy https://www.youtube.com/watch?v=OfqmR2lvU8E

i want to got the 1st way, this was more professional for me.

how can i send an selected nft to the owner? i just know how to mint to owner on polycan but dont now how i can choose the number of the nft there.

@goshaminsk
Copy link

Thanks for Polygon support!

I have an issue to verify a contract on the Mumbai Network

getting an error: Error in plugin @nomiclabs/hardhat-etherscan: Missing or invalid ApiKey

In .env file I added the API Key from polygon.io

Thank you

@liarco
Copy link
Member

liarco commented Mar 13, 2022

@nftkk you can specify the amount of NFTs to mint for an address, not the IDs.

@goshaminsk You are supposed to use the API key from polygonscan.

@ecerroni
Copy link

@goshaminsk did you also apply the changes mentioned here?
#57 (comment)

@ecerroni
Copy link

ecerroni commented Mar 13, 2022

how can i send an selected nft to the owner? i just know how to mint to owner on polycan but dont now how i can choose the number of the nft there.

When you use the mint function you just pass the amount of token you want to mint. This is true also if the minter is the owner.

If you want to mint specific NFTs for the owner you should do it on contract deploy. Let's say you want to mint the first 100 tokens in the contract. You should add a mint function like the following:

function initialOwnerMint(uint256 _mintAmount) public onlyOwner {
    uint256 supply = totalSupply();
    require(totalSupply() + _mintAmount <= maxSupply, 'Max supply exceeded!');
    require(supply + _mintAmount <= maxSupply, "max NFT limit exceeded");

    if (_mintAmount > 0 && initialOwnerMintPerformed == false) {
      _safeMint(_msgSender(), _mintAmount);
      initialOwnerMintPerformed = true;
    }
  }

You will need to call initialOwnerMint(100) in the constructor. You can also add the initial amount minted by the owner as an argument to the constructor for example

constructor(
    string memory _tokenName,
    string memory _tokenSymbol,
    uint256 _cost,
    uint256 _maxSupply,
    uint256 _maxMintAmountPerTx,
    string memory _hiddenMetadataUri,
    uint256 _numTokenMintByOwnerOnDeploy, // This is how many NFTs are sent to the two owner addresses on deploy
  ) ERC721A(_tokenName, _tokenSymbol) {
    cost = _cost;
    maxSupply = _maxSupply;
    maxMintAmountPerTx = _maxMintAmountPerTx;
    setHiddenMetadataUri(_hiddenMetadataUri);
    initialOwnerMint(_numTokenMintByOwnerOnDeploy);
  }

@goshaminsk
Copy link

goshaminsk commented Mar 13, 2022

You are supposed to use the API key from polygonscan.

Successfully verified contract on Etherscan

@liarco Thank you for you help!

@Berenike29
Copy link

Hi @liarco and @Jonas-Lieske Just wanted to let you know that I was able to deploy my contract successfully to the Polygon Mainnet using the updated contract! Thank you so, so much for making this possible!!

@ecerroni
Copy link

ecerroni commented Mar 17, 2022

I used this repo to deploy multiple versions of my smart contract on the Mumbai Testnet. I also imported them into Opensea with no issues. First time it took something like half an hour, but subsequent contracts deployed with the same owner address got imported automatically.

Once ready I deployed it to the Polygon Mainet following the same procedure. Everything went fine and the smart contract is on the blockchain: https://polygonscan.com/address/0xD15c3c9306ccD6D7c575a730A8cCb29bF98dB755.

However, here there is the issue. Opensea keeps giving me the following error when I try to import it:
We couldn't find this contract. Please ensure that this is a valid ERC721 or ERC1155 contract deployed on Polygon and that you have already minted items on the contract.

It's been more than 36 hours so far. Any idea on what I might have done wrong?

The only thing that comes to my mind is that I did yarn rename-contract UBW to rename it from TestBW. So I did it the first time for Testnet, and then again for Mainet. I've inspected the function and it does not seem to me that it could cause problems renaming it twice 🤔

Hopefully some of you can give me an insight.

EDIT:
I also found this possible solution I did not try though:
https://stackoverflow.com/questions/70352654/contract-not-getting-listen-on-opensea-mainnet-however-shows-nfts-in-metamask

@liarco
Copy link
Member

liarco commented Mar 18, 2022

Hi @ecerroni, I know that OpenSea doesn't allow you to import collections where no token has been minted yet. Can this be the issue in your case?

@ecerroni
Copy link

@liarco I've minted them all after contract deploy. Now totalSupply is equal to maxSupply. I guess that should be it 🤔

Here there is the contract https://polygonscan.com/address/0xD15c3c9306ccD6D7c575a730A8cCb29bF98dB755

I still hope it's all been about bad timing. Maybe I had no luck while deploying following Polygon’s network outage last week. Indeed they announced yesterday that they will implement a hard fork on Heimdall that I hope will somehow make my contract reemerge in front of OpenSea if that was actually the issue.

If that will not happen in the next few days then I have no idea what happened.

@Berenike29 @goshaminsk were you able to deploy on Polygon Mainet and import the contract on OpenSea or was it just on Testnets?

@Berenike29
Copy link

Hi @ecerroni yes I was able to deploy on the Polygon mainnet!

@ecerroni
Copy link

Hi @ecerroni yes I was able to deploy on the Polygon mainnet!

Thanks for chiming in. Were you also able to import the same contract on OpenSea and start selling items?

@liarco
Copy link
Member

liarco commented Mar 18, 2022

@ecerroni are you sure that your tokens are not under the "hidden" tab on Opensea? Is this your profile? https://opensea.io/waucollections

Because, since Polygon tokens are really cheap, OpenSea sets them as hidden by default in order to avoid showing promotional tokens on profile pages.


Anyway I run some tests together with other devs and this PR seems finally ready to be merged. This feature will be included in the next release asap, I want to thank everyone for contributing (especially @Jonas-Lieske for the initial implementation and testing).

@liarco liarco changed the title Added Polygon support Adding Polygon support Mar 18, 2022
@liarco liarco merged commit 7659440 into hashlips-lab:main Mar 18, 2022
@Prickheads
Copy link

Hi, thanks for all this work and help regarding deploying to Polygon.
I was able to follow along nicely and have managed to deploy a contract to Mumbai without issue.
I have followed all the steps with regards to the following links in this post:
steps
However, getting to the minting dapp, I keep getting the following error saying unsupported network while metamask is connect to Mumbai which the contract verified to with no issues.
Any ideas on why can't get the dapp to connect to the poly networks (same Unsupported Network if switch to Poly mainnet)?
dapp
Thanks again for the help and posting all this info and work!

@Prickheads
Copy link

Hi again, I have seemed to figure out my previous post and somehow had missed a comment from you regarding a couple changes in the the CollectionConfig.ts that you mentioned here:
#57 (comment)

I made these changes, changing the ethereum labels to polygon on these lines, and the Dapp seems to be working fine now!

Thanks once again for these posts and the help!
I'll be testing things out now on Mumbai thanks to you^^

@Dulzz69
Copy link

Dulzz69 commented Mar 21, 2022

Hello guys, first of all thank you very much for your works. I learnt so many things from you.
I want to confirm a thing. Can I create a DAPP from this for a already deployed smart contract that using remix? (I have the abi code). In other words, can I create a DAPP from this without this smart contract?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.