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

polygon finale #9464

Merged
merged 9 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 82 additions & 8 deletions app/assets/v2/js/cart-ethereum-polygon.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
const bulkCheckoutAddressPolygon = appCart.$refs.cart.network === 'mainnet'
? '0xb99080b9407436eBb2b8Fe56D45fFA47E9bb8877'
: '0x3E2849E2A489C8fE47F52847c42aF2E8A82B9973';

function objectMap(object, mapFn) {
return Object.keys(object).reduce(function(result, key) {
result[key] = mapFn(object[key]);
Expand Down Expand Up @@ -138,6 +134,12 @@ Vue.component('grantsCartEthereumPolygon', {
this.polygon.checkoutStatus = 'depositing';
},

getBulkCheckoutAddress() {
return appCart.$refs.cart.network === 'mainnet'
? '0xb99080b9407436eBb2b8Fe56D45fFA47E9bb8877'
: '0x3E2849E2A489C8fE47F52847c42aF2E8A82B9973';
mds1 marked this conversation as resolved.
Show resolved Hide resolved
},

handleError(e) {
appCart.$refs.cart.handleError(e);
},
Expand Down Expand Up @@ -246,6 +248,8 @@ Vue.component('grantsCartEthereumPolygon', {

// Send a batch transfer based on donation inputs
async checkoutWithPolygon() {
const bulkCheckoutAddressPolygon = this.getBulkCheckoutAddress();

try {

if (typeof ga !== 'undefined') {
Expand Down Expand Up @@ -311,6 +315,8 @@ Vue.component('grantsCartEthereumPolygon', {
},

async sendDonationTx(userAddress) {
const bulkCheckoutAddressPolygon = this.getBulkCheckoutAddress();

// Get our donation inputs
const bulkTransaction = new web3.eth.Contract(bulkCheckoutAbi, bulkCheckoutAddressPolygon);
const donationInputsFiltered = this.getDonationInputs();
Expand All @@ -334,11 +340,79 @@ Vue.component('grantsCartEthereumPolygon', {

// Estimates the total gas cost of a polygon checkout and sends it to cart.js
async estimateGasCost() {
// The below heuristics are used instead of `estimateGas()` so we can send the donation
// transaction before the approval txs are confirmed, because if the approval txs
// are not confirmed then estimateGas will fail.
/**
* The below heuristics are used instead of `estimateGas()` so we can send the donation
* transaction before the approval txs are confirmed, because if the approval txs
* are not confirmed then estimateGas will fail.
*/

let networkId = appCart.$refs.cart.networkId;

if (networkId !== '80001' && networkId !== '137' && appCart.$refs.cart.chainId !== '1' ||
appCart.$refs.cart.standardCheckoutInitiated) {
return;
}

let gasLimit = 0;

// If user has enough balance within Polygon, cost equals the minimum amount
let { isBalanceSufficient, requiredAmounts } = await this.hasEnoughBalanceInPolygon();

if (!isBalanceSufficient) {
// If we're here, user needs at least one L1 deposit, so let's calculate the total cost
requiredAmounts = objectMap(requiredAmounts, value => {
if (value.isBalanceSufficient == false) {
return value.amount;
}
});

for (const tokenSymbol in requiredAmounts) {
/**
* The below estimates were got by analyzing gas usages for deposit transactions
* on the RootChainManagerProxy contract. View the link below,
* https://goerli.etherscan.io/address/0xbbd7cbfa79faee899eaf900f13c9065bf03b1a74
*/
if (tokenSymbol === 'ETH') {
gasLimit += 94659; // add ~94.66k gas for ETH deposits
} else {
gasLimit += 103000; // add 103k gas for token deposits
mds1 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

// If we have a cart where all donations are in Dai, we use a linear regression to
// estimate gas costs based on real checkout transaction data, and add a 50% margin
const donationCurrencies = this.donationInputs.map(donation => donation.token);
const daiAddress = this.getTokenByName('DAI')?.addr;
const isAllDai = donationCurrencies.every((addr) => addr === daiAddress);

if (isAllDai) {
if (donationCurrencies.length === 1) {
// Special case since we overestimate here otherwise
return gasLimit + 65000;
}
// The Below curve found by running script with the repo https://github.com/mds1/Gitcoin-Checkout-Gas-Analysis.
// View the chart here -> https://chart-studio.plotly.com/~chibie/1/
return gasLimit + 10000 * donationCurrencies.length + 80000;
}

/**
* Otherwise, based on contract tests, we use the more conservative heuristic below to get
* a gas estimate. The estimates used here are based on testing the cost of a single
* donation (i.e. one item in the cart). Because gas prices go down with batched
* transactions, whereas this assumes they're constant, this gives us a conservative estimate
*/
gasLimit += this.donationInputs.reduce((accumulator, currentValue) => {
// const tokenAddr = currentValue.token?.toLowerCase();

if (currentValue.token === MATIC_ADDRESS) {
return accumulator + 25000; // MATIC donation gas estimate
}

return accumulator + 70000; // generic token donation gas estimate
}, 0);

return 70000;
return gasLimit;
},

// Returns true if user has enough balance within Polygon to avoid L1 deposit, false otherwise
Expand Down
37 changes: 21 additions & 16 deletions app/assets/v2/js/cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ document.addEventListener('dataWalletReady', async function(e) {
appCart.$refs['cart'].network = networkName;
appCart.$refs['cart'].sourceNetwork = networkName;
appCart.$refs['cart'].networkId = String(Number(web3.eth.currentProvider.chainId));
appCart.$refs['cart'].sourceNetworkId = appCart.$refs['cart'].networkId;
if (appCart.$refs.cart.autoSwitchNetwork) {
try {
await ethereum.request({
Expand Down Expand Up @@ -58,11 +59,13 @@ Vue.component('grants-cart', {
{ text: 'Transaction Hash', value: 'txid' }
],
autoSwitchNetwork: true,
checkoutRecommendationIsCompleted: false,
checkoutRecommendationIsComplete: false,
standardCheckoutInitiated: false,
chainId: '',
networkId: '',
network: 'mainnet',
sourceNetwork: 'mainnet',
sourceNetworkId: '1',
tabSelected: 'ETH',
tabIndex: null,
currentTokens: [], // list of all available tokens
Expand Down Expand Up @@ -392,24 +395,19 @@ Vue.component('grants-cart', {
const estimateZkSync = Number(this.zkSyncEstimatedGasCost); // zkSync gas cost estimate
const estimatePolygon = Number(this.polygonEstimatedGasCost); // polygon gas cost estimate
chibie marked this conversation as resolved.
Show resolved Hide resolved

const exit = (recommendation) => {
this.checkoutRecommendationIsCompleted = true;
return recommendation;
};

const compareWithL2 = (estimateL2, name) => {
if (estimateL1 < estimateL2) {
const savingsInGas = estimateL2 - estimateL1;
const savingsInPercent = Math.round(savingsInGas / estimateL2 * 100);

return exit({ name: 'Standard checkout', savingsInGas, savingsInPercent });
return { name: 'Standard checkout', savingsInGas, savingsInPercent };
}

const savingsInGas = estimateL1 - estimateL2;
const percentSavings = savingsInGas / estimateL1 * 100;
const savingsInPercent = percentSavings > 99 ? 99 : Math.round(percentSavings); // max value of 99%

return exit({ name, savingsInGas, savingsInPercent });
return { name, savingsInGas, savingsInPercent };
};

zkSyncComparisonResult = compareWithL2(estimateZkSync, 'zkSync');
Expand All @@ -418,12 +416,12 @@ Vue.component('grants-cart', {
polygonSavings = polygonComparisonResult.name === 'Polygon' ? polygonComparisonResult.savingsInPercent : 0;

if (zkSyncSavings > polygonSavings) {
return exit(zkSyncComparisonResult);
return zkSyncComparisonResult;
} else if (zkSyncSavings < polygonSavings) {
return exit(polygonComparisonResult);
return polygonComparisonResult;
}

return exit(zkSyncComparisonResult); // recommendation will be standard checkout
return zkSyncComparisonResult; // recommendation will be standard checkout
},

isHarmonyExtInstalled() {
Expand Down Expand Up @@ -809,8 +807,6 @@ Vue.component('grants-cart', {
* @param {String} name Token name, e.g. ETH or DAI
*/
getTokenByName(name, isPolygon = false) {
let token;

if (name === 'ETH' && !isPolygon) {
return {
addr: ETH_ADDRESS,
Expand All @@ -836,9 +832,7 @@ Vue.component('grants-cart', {
return token;
}

token = this.filterByChainId.filter(token => token.name === name)[0];

return token;
return this.filterByChainId.filter(token => token.name === name)[0];
},

async applyAmountToAllGrants(grant) {
Expand Down Expand Up @@ -1038,8 +1032,18 @@ Vue.component('grants-cart', {
}
},

resetNetwork() {
if (this.network === 'testnet') {
this.network = this.sourceNetwork;
this.networkId = this.sourceNetworkId;
}
},

// Standard L1 checkout flow
async standardCheckout() {
this.standardCheckoutInitiated = true;
this.resetNetwork();

try {
// Setup -----------------------------------------------------------------------------------
this.isCheckoutOngoing = true;
Expand All @@ -1066,6 +1070,7 @@ Vue.component('grants-cart', {
} catch (err) {
this.handleError(err);
}
this.standardCheckoutInitiated = false;
},

/**
Expand Down
4 changes: 1 addition & 3 deletions app/grants/templates/grants/cart/eth.html
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,9 @@ <h4 class="col gc-font-base text-dark p-0">Summary</h4>
<div v-if="zkSyncUnsupportedTokens.length > 0">
zkSync checkout not supported due to [[ zkSyncUnsupportedTokens.join(', ') ]]
</div>
{% if is_staff %}
<div v-if="polygonUnsupportedTokens.length > 0">
Polygon checkout not supported due to [[ polygonUnsupportedTokens.join(', ') ]]
</div>
{% endif %}
</div>
<div v-else-if="!isNaN(checkoutRecommendation.savingsInPercent)">
💡 Save <span class="text-primary">~[[ checkoutRecommendation.savingsInPercent ]]%</span>
Expand All @@ -173,7 +171,7 @@ <h4 class="col gc-font-base text-dark p-0">Summary</h4>
<!-- Checkout buttons -->
<div class="row justify-content-end">
<div class="btn-group flex-column flex-grow-1 flex-md-grow-0 flex-md-row" role="group" aria-label="Checkout buttons">

{% if is_staff %}
chibie marked this conversation as resolved.
Show resolved Hide resolved
<!-- CHECKOUT WITH POLYGON -->
<grants-cart-ethereum-polygon
Expand Down
16 changes: 12 additions & 4 deletions app/grants/templates/grants/detail/template-grant-details.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,18 @@ <h2>[[grant.title]]</h2>
<i class="far fa-copy"></i>
</copy-clipboard>
</span>
<a target="_blank" :href="`https://zkscan.io/explorer/accounts/${grant.admin_address}`"
class="col-auto badge badge-pill bg-lightpurple text-primary font-weight-semibold" id="wallet-zkscan-link">
L2
</a>
<span>
<a target="_blank" :href="`https://zkscan.io/explorer/accounts/${grant.admin_address}`"
class="col-auto badge badge-pill bg-lightpurple text-primary font-weight-semibold" id="wallet-zkscan-link">
zkSync
</a>
{% if is_staff %}
<a target="_blank" :href="`https://polygonscan.com/address/${grant.admin_address}`"
class="col-auto badge badge-pill bg-lightpurple text-primary font-weight-semibold" id="wallet-polygonscan-link">
Polygon
</a>
{% endif %}
</span>
</template>

<!-- ZCASH -->
Expand Down
2 changes: 1 addition & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ django-ipware==2.0.2
geoip2==2.8.0
django-silk==2.0.0
django-extensions==2.2.1
ipdb==0.11
ipdb==0.13.9
mds1 marked this conversation as resolved.
Show resolved Hide resolved
django-autotranslate==1.1.1
svgutils==0.3.0
watchdog==0.9.0
Expand Down