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

feat(unlock-app): adding burnKey to unlock-js #15132

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions packages/unlock-js/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changes

# 0.50.0

- adding `burnKey` to WalletService

# 0.49.2

- adding `setMerkleRoot` to WalletService
Expand Down
2 changes: 1 addition & 1 deletion packages/unlock-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@unlock-protocol/unlock-js",
"version": "0.49.2",
"version": "0.50.0",
"description": "This module provides libraries to include Unlock APIs inside a Javascript application.",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
83 changes: 83 additions & 0 deletions packages/unlock-js/src/PublicLock/v10/burnKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
export default async function (
{
lockAddress,
tokenId,
}: {
lockAddress: string
tokenId: number
},
transactionOptions: {
runEstimate?: boolean
gasLimit?: bigint
maxFeePerGas?: string
maxPriorityFeePerGas?: string
gasPrice?: string
} = {},
callback: (error: any, hash: string, transactionPromise: any) => void
) {
const lockContract = await this.getLockContract(lockAddress)

if (!tokenId) {
throw new Error('Missing tokenId.')
}

// Estimate gas. Bump by 30% because estimates are wrong!
if (!transactionOptions.gasLimit) {
try {
// To get good estimates we need the gas price, because it matters in the actual execution (UDT calculation takes it into account)
// TODO remove once we move to use block.baseFee in UDT calculation
const { gasPrice, maxFeePerGas, maxPriorityFeePerGas } =
await this.provider.getFeeData()

if (maxFeePerGas && maxPriorityFeePerGas) {
transactionOptions.maxFeePerGas = maxFeePerGas
transactionOptions.maxPriorityFeePerGas = maxPriorityFeePerGas
} else {
transactionOptions.gasPrice = gasPrice
}

const gasLimitPromise = lockContract.burnKey.estimateGas(
tokenId,
transactionOptions
)
const gasLimit = await gasLimitPromise
// Remove the gas prices settings for the actual transaction (the wallet will set them)
delete transactionOptions.maxFeePerGas
delete transactionOptions.maxPriorityFeePerGas
delete transactionOptions.gasPrice
transactionOptions.gasLimit = gasLimit
} catch (error) {
console.error(
'We could not estimate gas ourselves. Let wallet do it.',
error
)
delete transactionOptions.maxFeePerGas
delete transactionOptions.maxPriorityFeePerGas
delete transactionOptions.gasPrice
}
}

const transactionRequestpromise = lockContract.burnKey.populateTransaction(
[tokenId],
transactionOptions
)

const transactionRequest = await transactionRequestpromise

if (transactionOptions.runEstimate) {
const estimate = this.signer.estimateGas(transactionRequest)
return {
transactionRequest,
estimate,
}
}

const transactionPromise = this.signer.sendTransaction(transactionRequest)

const hash = await this._handleMethodCall(transactionPromise)

if (callback) {
callback(null, hash, await transactionPromise)
}
return hash
}
2 changes: 2 additions & 0 deletions packages/unlock-js/src/PublicLock/v10/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import getLock from './getLock'
import renewMembershipFor from './renewMembershipFor'
import v9 from '../v9'
import getPurchaseKeysArguments from './getPurchaseKeysArguments'
import burnKey from './burnKey'
import preparePurchaseKeysTx from './preparePurchaseKeysTx'
import preparePurchaseKeyTx from './preparePurchaseKeyTx'

Expand Down Expand Up @@ -87,6 +88,7 @@ export default {
setKeyManagerOf,
transferFrom,
setGasRefundValue,
burnKey,
preparePurchaseKeyTx,
preparePurchaseKeysTx,
}
59 changes: 59 additions & 0 deletions packages/unlock-js/src/__tests__/integration/lock/burnKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { describe, it, expect, beforeAll } from 'vitest'
import { versionEqualOrAbove } from '../../helpers/integration'

let walletService, web3Service, lockAddress, accounts, chainId

export default ({ publicLockVersion }) => {
if (versionEqualOrAbove(publicLockVersion, 'v10')) {
describe('burnKey', () => {
let keyOwner
let tokenId
let transactionHash

beforeAll(async () => {
;({ walletService, web3Service, lockAddress, accounts, chainId } =
global.suiteData)

keyOwner = accounts[10]

tokenId = await walletService.purchaseKey({
lockAddress,
owners: keyOwner,
})

expect(
await web3Service.isValidKey(lockAddress, tokenId, chainId)
).toBe(true)

// then extend existing expired key
await walletService.burnKey(
{
lockAddress,
tokenId,
},
{} /** transactionOptions */,

(error, hash) => {
if (error) {
throw error
}
transactionHash = hash
}
)
await web3Service.getKeyByTokenId(lockAddress, tokenId, chainId)
})

it('should have yielded a transaction hash', () => {
expect.assertions(1)
expect(transactionHash).toMatch(/^0x[0-9a-fA-F]{64}$/)
})

it('should have burned the key', async () => {
expect.assertions(1)
expect(
await web3Service.isValidKey(lockAddress, tokenId, chainId)
).toBe(false)
})
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import setBaseTokenURI from './lock/setBaseTokenURI'
import setEventHooks from './lock/setEventHooks'
import transferFrom from './lock/transferFrom'
import lendKey from './lock/lendKey'
import burnKey from './lock/burnKey'

// Increasing timeouts

Expand Down Expand Up @@ -145,13 +146,15 @@ describe.each(UnlockVersionNumbers)('Unlock %s', (unlockVersion) => {

// lock tests
approveBeneficiary(testSetupArgs)
burnKey(testSetupArgs)
cancelAndRefund(testSetupArgs)
expireAndRefundFor(testSetupArgs)
extendKey(testSetupArgs)
grantKey(testSetupArgs)
grantKeyExtension(testSetupArgs)
grantKeys(testSetupArgs)
keyGranter(testSetupArgs)
lendKey(testSetupArgs)
maxKeysPerAddress(testSetupArgs)
mergeKeys(testSetupArgs)
purchaseKey(testSetupArgs)
Expand All @@ -162,12 +165,11 @@ describe.each(UnlockVersionNumbers)('Unlock %s', (unlockVersion) => {
setMaxNumberOfKeys(testSetupArgs)
shareKeyToAddress(testSetupArgs)
shareKeyToTokenId(testSetupArgs)
transferFrom(testSetupArgs)
updateKeyPrice(testSetupArgs)
updateLockName(testSetupArgs)
updateLockSymbol(testSetupArgs)
withdrawFromLock(testSetupArgs)
transferFrom(testSetupArgs)
lendKey(testSetupArgs)
})
})
})
15 changes: 15 additions & 0 deletions packages/unlock-js/src/walletService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,21 @@ export default class WalletService extends UnlockService {
return version.grantKeys.bind(this)(params, transactionOptions, callback)
}

async burnKey(
params: {
lockAddress: string
tokenId: string
},
transactionOptions?: TransactionOptions,
callback?: WalletServiceCallback
) {
if (!params.lockAddress) {
throw new Error('Missing lockAddress')
}
const version = await this.lockContractAbiVersion(params.lockAddress)
return version.burnKey.bind(this)(params, transactionOptions, callback)
}

/**
* Grant key extension. This implementation requires the following
* @param {object} params:
Expand Down
Loading
Loading