Skip to content

Instantly share code, notes, and snippets.

@sbauch
Created September 26, 2021 18:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sbauch/a3405609f2fe858c4dff2ffde81c88d3 to your computer and use it in GitHub Desktop.
Save sbauch/a3405609f2fe858c4dff2ffde81c88d3 to your computer and use it in GitHub Desktop.
hacky little loot bag => attribute points + meta tx
import { parseEther, parseUnits } from '@ethersproject/units';
import { BigNumber, Contract, providers, utils, Wallet } from 'ethers';
import { getBagsInWallet } from 'loot-sdk';
import { MongoClient } from 'mongodb';
import { getSession } from 'next-auth/client';
import {
abi as arenaAbi,
address as arenaAddress,
} from '../../abis/WrasslingArenaV2.json';
const messageKey = (tokenId, nonce) =>
`Upgrading Wrassler #${tokenId}. \n\nUsing Loot grants you free, extra attribute points. You can only upgrade with Loot once. Upgrading does not spend or burn your Loot.\n\nNonce: ${nonce}`;
const weapon = [
'Warhammer',
'Quarterstaff',
'Maul',
'Mace',
'Club',
'Katana',
'Falchion',
'Scimitar',
'Long Sword',
'Short Sword',
'Ghost Wand',
'Grave Wand',
'Bone Wand',
'Wand',
'Grimoire',
'Chronicle',
'Tome',
'Book',
];
const chest = [
'Divine Robe',
'Silk Robe',
'Linen Robe',
'Robe',
'Shirt',
'Demon Husk',
'Dragonskin Armor',
'Studded Leather Armor',
'Hard Leather Armor',
'Leather Armor',
'Holy Chestplate',
'Ornate Chestplate',
'Plate Mail',
'Chain Mail',
'Ring Mail',
];
const head = [
'Ancient Helm',
'Ornate Helm',
'Great Helm',
'Full Helm',
'Helm',
'Demon Crown',
"Dragon's Crown",
'War Cap',
'Leather Cap',
'Cap',
'Crown',
'Divine Hood',
'Silk Hood',
'Linen Hood',
'Hood',
];
const waist = [
'Ornate Belt',
'War Belt',
'Plated Belt',
'Mesh Belt',
'Heavy Belt',
'Demonhide Belt',
'Dragonskin Belt',
'Studded Leather Belt',
'Hard Leather Belt',
'Leather Belt',
'Brightsilk Sash',
'Silk Sash',
'Wool Sash',
'Linen Sash',
'Sash',
];
const foot = [
'Holy Greaves',
'Ornate Greaves',
'Greaves',
'Chain Boots',
'Heavy Boots',
'Demonhide Boots',
'Dragonskin Boots',
'Studded Leather Boots',
'Hard Leather Boots',
'Leather Boots',
'Divine Slippers',
'Silk Slippers',
'Wool Shoes',
'Linen Shoes',
'Shoes',
];
const hand = [
'Holy Gauntlets',
'Ornate Gauntlets',
'Gauntlets',
'Chain Gloves',
'Heavy Gloves',
"Demon's Hands",
'Dragonskin Gloves',
'Studded Leather Gloves',
'Hard Leather Gloves',
'Leather Gloves',
'Divine Gloves',
'Silk Gloves',
'Wool Gloves',
'Linen Gloves',
'Gloves',
];
const groupings = {
weapon,
chest,
head,
waist,
foot,
hand,
};
const itemForAttribute = {
determination: 'chest',
speed: 'foot',
power: 'hand',
awareness: 'head',
resilience: 'waist',
aggression: 'weapon',
};
const pointsForItem = (item, type) => {
const variants = groupings[type];
const v = variants.find((variant) => new RegExp(`.*${variant}.*`).test(item));
const tier = (variants.indexOf(v) % 3) + 1;
let points = tier * 50;
if (item[0] == '"') points += 25;
if (/.*of A-za-z*$/.test(item)) points += 50;
if (/.*\+1$/.test(item)) points += 100;
return points;
};
const pointsForBag = (bag, upgradeParams) => {
return Object.entries(upgradeParams).reduce((totals, [key, _value]) => {
return {
...totals,
[key]:
totals[key] +
pointsForItem(bag[itemForAttribute[key]], itemForAttribute[key]),
};
}, upgradeParams);
};
export default async (req, res) => {
const session = await getSession({ req });
if (!session) {
return res.send(
JSON.stringify({
success: false,
error: 'No session',
}),
);
}
const { sig, tokenId, contractAddress } = JSON.parse(req.body);
const address = utils.verifyMessage(
messageKey(tokenId, session.ethNonce),
sig,
);
const client = await MongoClient.connect(process.env.DATABASE_URL);
const db = client.db();
const user = await db
.collection('users')
.findOne({ address: session.address });
if (user.usedLoot) {
return res.send(
JSON.stringify({
success: false,
error: 'Already used loot',
}),
);
}
const lootBags = await getBagsInWallet(address.toLowerCase());
console.warn(address, tokenId, lootBags);
const maticProvider = new providers.JsonRpcProvider(
process.env.MATIC_RPC_URL,
);
const wallet = new Wallet(process.env.GAS_WALLET_PRIVATE_KEY, maticProvider);
const betaContract = new Contract(arenaAddress, arenaAbi, wallet);
const baseParams = {
aggression: 0,
awareness: 0,
determination: 0,
power: 0,
resilience: 0,
speed: 0,
};
const upgradeParams = lootBags.reduce((totals, bag) => {
const upgradeParams = pointsForBag(bag, baseParams);
for (const [attribute, points] of Object.entries(upgradeParams)) {
totals[attribute] += points;
}
return totals;
}, baseParams);
const tx = await betaContract.upgradeWrassler(
contractAddress,
BigNumber.from(tokenId),
Object.values(upgradeParams),
{
value: parseEther('0.01').mul(
BigNumber.from(
Object.values(upgradeParams).reduce(
(v: number, total: number) => (total += v),
0,
),
),
),
gasPrice: parseUnits('25', 'gwei'),
gasLimit: 15_000_000,
},
);
if (tx.hash) {
await db
.collection('users')
.replaceOne({ address: session.address }, { ...user, usedLoot: true });
return res.send(
JSON.stringify({
success: true,
txHash: tx.hash,
}),
);
}
return res.send(
JSON.stringify({
success: false,
error: 'Transaction error',
}),
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment