PolicyPool

This is the main contract of the protocol.

_There's a single instance of PolicyPool contract for a given deployment of the protocol. It stores the registry of components (eTokens, PremiumsAccounts, and RiskModules). It also tracks the active exposure and exposure limit per risk module.

This is also the contract that receives and sends the underlying asset (currency, typically USDC). The currency spending approvals should be done to this protocol for deposits or premium payments.

This contract implements the ERC721 standard, because it mints and NFT for each policy created. The property of the NFT represents the one that will receive the payout.

The active policies are tracked in policies as hashes, but for gas optimization we just store the hash of the policy struct, and the struct needs to be stored off-chain and provided on every subsequent call.

Types

ComponentStatus

Different statuses that a component ({PremiumsAccount}, {EToken} or {RiskModule} can have.

enum ComponentStatus {
  inactive,
  active,
  deprecated,
  suspended
}

ComponentKind

Enum of the different kind of top level components that can be plugged into the pool. Each one corresponds with the {EToken}, {RiskModule} and {PremiumsAccount} respectively.

enum ComponentKind {
  unknown,
  eToken,
  riskModule,
  premiumsAccount
}

Component

Struct to keep the state and type of the components installed

The kind never changes. The status initially is active and can be changes with {PolicyPool-changeComponentStatus} and {PolicyPool-removeComponent}.

struct Component {
  enum PolicyPool.ComponentStatus status;
  enum PolicyPool.ComponentKind kind;
}

Exposure

struct Exposure {
  uint128 active;
  uint128 limit;
}

Variables

HOLDER_GAS_LIMIT

uint256 HOLDER_GAS_LIMIT

_currency

contract IERC20Metadata _currency

_treasury

address _treasury

Address of Ensuro's treasury that receives the protocol fees.

_components

mapping(contract IPolicyPoolComponent => struct PolicyPool.Component) _components

Mapping of installed components (see {EToken}, {RiskModule}, {PremiumsAccount}) in the PolicyPool.

_policies

mapping(uint256 => bytes32) _policies

Mapping that stores the active policies (the policyId is the key).

It just saves the hash of the policies, the full {Policy-PolicyData} struct has to be sent for each operation (hash is used to verify).

_nftBaseURI

string _nftBaseURI

Base URI for the minted policy NFTs.

_exposureByRm

mapping(contract IRiskModule => struct PolicyPool.Exposure) _exposureByRm

Mapping of current exposures and limits for each risk module.

Events

TreasuryChanged

event TreasuryChanged(address oldTreasury, address newTreasury)

Event emitted when the treasury (who receives ensuroCommission) changes

Parameters

Name Type Description
oldTreasury address The address of the treasury before the change
newTreasury address The address of the treasury after the change

BaseURIChanged

event BaseURIChanged(string oldBaseURI, string newBaseURI)

Event emitted when the baseURI (for policy NFTs) changes

Parameters

Name Type Description
oldBaseURI string The baseURI before the change
newBaseURI string The baseURI after the change

ComponentStatusChanged

event ComponentStatusChanged(contract IPolicyPoolComponent component, enum PolicyPool.ComponentKind kind, enum PolicyPool.ComponentStatus newStatus)

Event emitted when a new component added/removed to the pool or the status changes.

Parameters

Name Type Description
component contract IPolicyPoolComponent The address of the component, it can be an {EToken}, {RiskModule} or {PremiumsAccount}
kind enum PolicyPool.ComponentKind Value indicating the kind of component. See {ComponentKind}
newStatus enum PolicyPool.ComponentStatus The status of the component after the operation. See {ComponentStatus}

ExpirationNotificationFailed

event ExpirationNotificationFailed(uint256 policyId, contract IPolicyHolder holder)

Event emitted when a IPolicyHolder reverts on the expiration notification. The operation doesn't reverts

Parameters

Name Type Description
policyId uint256 The id of the policy being expired
holder contract IPolicyHolder The address of the contract that owns the policy

ExposureLimitChanged

event ExposureLimitChanged(contract IRiskModule riskModule, uint128 oldLimit, uint128 newLimit)

Event emitted when the exposure limit for a given risk module is changed

Parameters

Name Type Description
riskModule contract IRiskModule The risk module whose limit will be changed
oldLimit uint128 Exposure limit before the change
newLimit uint128 Exposure limit after the change

Deposit

event Deposit(contract IEToken eToken, address sender, address owner, uint256 amount)

Event emitted for every deposit into an eToken

Parameters

Name Type Description
eToken contract IEToken The eToken receiving the funds
sender address The sender of the funds (the user calling deposit or depositWithPermit)
owner address The user that will receive the minted eTokens
amount uint256 Amount in currency() paid for the eTokens (equal to the amount of eTokens received)

Withdraw

event Withdraw(contract IEToken eToken, address sender, address receiver, address owner, uint256 amount)

Event emitted for every withdrawal from an eToken

Parameters

Name Type Description
eToken contract IEToken The eToken where the withdrawal will be done
sender address The user calling the withdraw method. Must be the owner or have spending approval from it.
receiver address The user that receives the resulting funds (currency())
owner address The owner of the burned eTokens
amount uint256 Amount in currency() that will be received by receiver.

Errors

NoZeroCurrency

error NoZeroCurrency()

Constructor error when address(0) is sent as currency()

NoZeroTreasury

error NoZeroTreasury()

Constructor error (or setTreasury) when address(0) is sent as treasury()

NoEmptyName

error NoEmptyName()

Initialization error when empty name for the ERC721 is sent

NoEmptySymbol

error NoEmptySymbol()

Initialization error when empty symbol for the ERC721 is sent

UpgradeCannotChangeCurrency

error UpgradeCannotChangeCurrency()

Thrown when trying to change the currency during an upgrade

ComponentAlreadyInThePool

error ComponentAlreadyInThePool()

Error when trying to add a component that was already added to the PolicyPool

ComponentNotLinkedToThisPool

error ComponentNotLinkedToThisPool()

Error when trying to add a component that isn't linked to this pool (.policyPool() != this)

ComponentNotTheRightKind

error ComponentNotTheRightKind(contract IPolicyPoolComponent component, enum PolicyPool.ComponentKind expectedKind)

Raised when a component is not of the right kind

It might happen if a component declared as ComponentKind.eToken doesn't support the IEToken interface (or similar) or when in a given operation we expect a component to be a risk module and the stored kind is different.

ComponentNotDeprecated

error ComponentNotDeprecated()

Error when a component is not deprecated for the operation (see removeComponent), when it must.

ComponentInUseCannotRemove

error ComponentInUseCannotRemove(enum PolicyPool.ComponentKind kind, uint256 amount)

Error when trying to remove a component that is still in use.

The "in use" definition can change from one component to the other. For eToken in use means totalSupply() != 0. For PremiumsAccount means purePremiums() != 0. For RiskModule means activeExposure() != 0.

ComponentNotFound

error ComponentNotFound()

Error when a component is not found in the pool (status = 0 = inactive)

ComponentNotFoundOrNotActive

error ComponentNotFoundOrNotActive()

Error when a component is not found in the pool or is not active (status != active)

InvalidComponentStatus

error InvalidComponentStatus()

Thrown when attempting to set a component status to inactive via changeComponentStatus, use removeComponent() instead.

ComponentMustBeActiveOrDeprecated

error ComponentMustBeActiveOrDeprecated()

Error when a component is not active or deprecated. Happens on some operations like eToken withdrawals or policy resolutions that accept the component might be active or deprecated and isn't on any of those states.

OnlyRiskModuleAllowed

error OnlyRiskModuleAllowed()

Error when a method intented to be called by riskModule (and by policy's risk module) is called by someone else.

InvalidNotificationResponse

error InvalidNotificationResponse(bytes4 response)

Raised when IPolicyHolder doesn't return the expected selector answer when notified of policy payout, replacement or cancellation.

PolicyAlreadyExists

error PolicyAlreadyExists(uint256 policyId)

Thrown when attempting to create a policy with an ID that already exists

PolicyAlreadyExpired

error PolicyAlreadyExpired(uint256 policyId)

Thrown when attempting to process an action (other than expiration) on a policy after its expiration date

PolicyNotFound

error PolicyNotFound(uint256 policyId)

Thrown when attempting to execute an action on a policy that does not exist (or was already expired)

PolicyNotExpired

error PolicyNotExpired(uint256 policyId, uint40 expiration, uint256 now)

Thrown when attempting to expire a policy, but the policy is still active (policy.expiration > block.timestamp)

Parameters

Name Type Description
policyId uint256 The ID of the policy that is not yet expired
expiration uint40 The timestamp when the policy expires
now uint256 The current block timestamp

InvalidPolicyReplacement

error InvalidPolicyReplacement(struct Policy.PolicyData oldPolicy, struct Policy.PolicyData newPolicy)

Thrown when attempting to replace a policy with an invalid replacement

This could occur if the policies have a different start, or if any of the premium components of the newPolicy are lower than the same component of the original policy.

Parameters

Name Type Description
oldPolicy struct Policy.PolicyData The original policy data
newPolicy struct Policy.PolicyData The proposed replacement policy data

InvalidPolicyCancellation

error InvalidPolicyCancellation(struct Policy.PolicyData policyToCancel, uint256 purePremiumRefund, uint256 jrCocRefund, uint256 srCocRefund)

Thrown when attempting to cancel a policy with invalid refunds

The refunds amounts can never exceed the original premium components.

Parameters

Name Type Description
policyToCancel struct Policy.PolicyData The data of the policy being cancelled
purePremiumRefund uint256 The amount to refund from pure premium charged
jrCocRefund uint256 The amount to refund from jrCoc charged
srCocRefund uint256 The amount to refund from srCoc charged

PayoutExceedsLimit

error PayoutExceedsLimit(uint256 payout, uint256 policyPayout)

Thrown when a requested payout exceeds the policy's maximum payout limit

ExposureLimitExceeded

error ExposureLimitExceeded(uint128 activeExposure, uint128 exposureLimit)

Thrown when an action would cause the active exposure to exceed the configured limit

InvalidReceiver

error InvalidReceiver(address receiver)

Thrown when an invalid receiver address (address(0)) is provided as received of deposit or withdraw

Public Functions

constructor

constructor(contract IERC20Metadata currency_) public

initialize

function initialize(string name_, string symbol_, address treasury_) public

Initializes a Policy Pool

Parameters

Name Type Description
name_ string The name of the ERC721 token.
symbol_ string The symbol of the ERC721 token.
treasury_ address The address of the treasury that will receive the protocol fees.

supportsInterface

function supportsInterface(bytes4 interfaceId) public view virtual returns (bool)

pause

function pause() public

Pauses the contract.

When the contract is paused, several operations are rejected: deposits, withdrawals, new policies, policy resolution and expiration, nft transfers.

unpause

function unpause() public

Unpauses the contract.

All the operations disabled when the contract was paused are re-enabled.

currency

function currency() external view virtual returns (contract IERC20Metadata)

Reference to the main currency (ERC20, e.g. USDC) used in the protocol

setTreasury

function setTreasury(address treasury_) external

Changes the address of the treasury, the one that receives the protocol fees.

Emits

TreasuryChanged
with the previous and current treasury

treasury

function treasury() external view returns (address)

Address of the treasury, that receives protocol fees.

addComponent

function addComponent(contract IPolicyPoolComponent component, enum PolicyPool.ComponentKind kind) external

Adds a new component (either an {EToken}, {RiskModule} or {PremiumsAccount}) to the protocol.

The component status will be active.

Parameters

Name Type Description
component contract IPolicyPoolComponent The address of component contract. Must be an {EToken}, {RiskModule} or {PremiumsAccount} linked to this specific {PolicyPool} and matching the kind specified in the next paramter.
kind enum PolicyPool.ComponentKind The type of component to be added.

Throws

ComponentNotTheRightKind
When there's a mismatch between the specified kind and supported interface

Emits

ComponentStatusChanged
with status active.

removeComponent

function removeComponent(contract IPolicyPoolComponent component) external

Removes a component from the protocol

The component needs to be in deprecated status before doing this operation.

Parameters

Name Type Description
component contract IPolicyPoolComponent The address of component contract. Must be a component added before.

Emits

ComponentStatusChanged
with status inactive.

changeComponentStatus

function changeComponentStatus(contract IPolicyPoolComponent component, enum PolicyPool.ComponentStatus newStatus) external

Changes the status of a component.

Parameters

Name Type Description
component contract IPolicyPoolComponent The address of component contract. Must be a component added before.
newStatus enum PolicyPool.ComponentStatus The new status, must be either active, deprecated or suspended.

Throws

InvalidComponentStatus()
when newStatus is inactive (use removeComponent() instead)

Emits

ComponentStatusChanged
with the new status.

getComponentStatus

function getComponentStatus(contract IPolicyPoolComponent component) external view returns (enum PolicyPool.ComponentStatus)

Returns the status of a component.

Parameters

Name Type Description
component contract IPolicyPoolComponent The address of the component

Return Values

Name Type Description
[0] enum PolicyPool.ComponentStatus The status of the component. See {ComponentStatus}

deposit

function deposit(contract IEToken eToken, uint256 amount, address receiver) external

Deposits liquidity into an eToken

Forwards the call to {EToken-deposit}, after transferring the funds. The user will receive etokens for the same amount deposited.

Parameters

Name Type Description
eToken contract IEToken The address of the eToken to which the user wants to provide liquidity
amount uint256 The amount to deposit
receiver address The user that will receive the minted tokens

Pre-conditions

  • msg.sender approved the spending of currency() for at least amount
  • eToken is an active eToken installed in the pool.

Emits

EToken-Transfer
from 0x0 to `receiver`, reflects the eTokens minted.
ERC20-Transfer
from `msg.sender` to address(eToken)

depositWithPermit

function depositWithPermit(contract IEToken eToken, uint256 amount, address receiver, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external

Deposits liquidity into an eToken, EIP-2612 compatible version.

Forwards the call to {EToken-deposit}, after transferring the funds. The user will receive etokens for the same amount deposited. EIP-2612 compatible version, allows sending a signed permit in the same operation.

Parameters

Name Type Description
eToken contract IEToken The address of the eToken to which the user wants to provide liquidity
amount uint256 The amount to deposit
receiver address The user that will receive the minted tokens
deadline uint256 The deadline of the permit
v uint8 Component of the secp256k1 signature
r bytes32 Component of the secp256k1 signature
s bytes32 Component of the secp256k1 signature

Pre-conditions

  • msg.sender approved the spending of currency() for at least amount
  • eToken is an active eToken installed in the pool.

Emits

EToken-Transfer
from 0x0 to `receiver`, reflects the eTokens minted.
ERC20-Transfer
from `msg.sender` to address(eToken)

withdraw

function withdraw(contract IEToken eToken, uint256 amount, address receiver, address owner) external returns (uint256 amountWithdrawn)

Withdraws an amount from an eToken

Forwards the call to {EToken-withdraw}. amount of eTokens will be burned and the user will receive the same amount in currency().

Parameters

Name Type Description
eToken contract IEToken The address of the eToken from where the user wants to withdraw liquidity
amount uint256 The amount to withdraw. If equal to type(uint256).max, means full withdrawal. If the balance is not enough or can't be withdrawn (locked as SCR), it withdraws as much as it can, but doesn't fails.
receiver address The user that will receive the resulting currency()
owner address The user that owns the eTokens (must be msg.sender or have allowance)

Return Values

Name Type Description
amountWithdrawn uint256 Returns the actual amount withdrawn.

Pre-conditions

  • eToken is an active (or deprecated) eToken installed in the pool.

Emits

EToken-Transfer
from `owner` to `0x0`, reflects the eTokens burned.
ERC20-Transfer
from address(eToken) to `receiver`

newPolicy

function newPolicy(struct Policy.PolicyData policy, address payer, address policyHolder, uint96 internalId) external returns (uint256)

Creates a new Policy

It charges the premium and distributes it to the different parties (PremiumsAccount, ETokens, treasury)

Parameters

Name Type Description
policy struct Policy.PolicyData A policy created with {Policy-initialize}
payer address The address that will pay for the premium
policyHolder address The address of the policy holder
internalId uint96 A unique id within the RiskModule, that will be used to compute the policy id

Return Values

Name Type Description
[0] uint256 The policy id, identifying the NFT and the policy

Pre-conditions

  • msg.sender must be an active RiskModule
  • rm.premiumsAccount() must be an active PremiumsAccount
  • payer approved the spending of currency() for at least policy.premium
  • internalId must be unique within the risk module (msg.sender) and not used before

Throws

PolicyAlreadyExists
when reusing an internalId

Emits

NewPolicy
with all the details about the policy
ERC20-Transfer
transfers from `payer` to the different receivers of the premium
(see Premium Split in the docs)

replacePolicy

function replacePolicy(struct Policy.PolicyData oldPolicy, struct Policy.PolicyData newPolicy_, address payer, uint96 internalId) external returns (uint256)

Replaces a policy with another

After this call, the oldPolicy is no longer active and a new policy is created. Diferencial changes to premiums and locked SCR.

Parameters

Name Type Description
oldPolicy struct Policy.PolicyData A policy created previously and not expired
newPolicy_ struct Policy.PolicyData A policy created with {Policy-initialize}
payer address The address that will pay for the premium difference
internalId uint96 A unique id within the RiskModule, that will be used to compute the policy id

Return Values

Name Type Description
[0] uint256 The policy id, identifying the NFT and the policy

Pre-conditions

  • msg.sender must be an active RiskModule
  • rm.premiumsAccount() must be an active PremiumsAccount
  • payer approved the spending of currency() for at least newPolicy_.premium - oldPolicy.premium
  • internalId must be unique within policy.riskModule and not used before

Throws

PolicyAlreadyExpired
when trying to replace an expired policy
InvalidPolicyReplacement
when trying to reduce some of the premium componentsa

Emits

PolicyReplaced
with the ids of the new and replaced policy
NewPolicy
with all the details of the new policy

cancelPolicy

function cancelPolicy(struct Policy.PolicyData policyToCancel, uint256 purePremiumRefund, uint256 jrCocRefund, uint256 srCocRefund) external

Cancels a policy, doing optional refunds of parts of the premium.

After this call the policy is not claimable and funds are unlocked

Parameters

Name Type Description
policyToCancel struct Policy.PolicyData A policy created previously and not expired, that will be cancelled
purePremiumRefund uint256 The amount to refund from pure premiums (<= policyToCancel.purePremium)
jrCocRefund uint256 The amount to refund from jrCoc (<= policyToCancel.jrCoc)
srCocRefund uint256 The amount to refund from srCoc (<= policyToCancel.jrCoc)

Pre-conditions

  • msg.sender must be an active or deprecated RiskModule
  • Policy not expired
  • Events:

Emits

PolicyCancelled
with the refund amounts
ERC20-Transfer
transfers of the refunds amount to the policy holder

expirePolicy

function expirePolicy(struct Policy.PolicyData policy) external

Expires a policy, unlocked the solvency.

Resolves a policy with a payout 0, unlocking the solvency. Can be called by anyone, but only after Policy.expiration.

Parameters

Name Type Description
policy struct Policy.PolicyData A policy previously created with newPolicy

Pre-conditions

  • policy: must be a Policy not resolved before
  • policy.expiration <= block.timestamp

Emits

PolicyResolved
with the payout == 0

resolvePolicy

function resolvePolicy(struct Policy.PolicyData policy, uint256 payout) external

Resolves a policy with a payout, sending the payment to the owner of the policy NFT.

After this call the policy is no longer active and the funds have been unlocked.

Parameters

Name Type Description
policy struct Policy.PolicyData A policy previously created with newPolicy
payout uint256 The amount to pay to the policyholder

Pre-conditions

  • msg.sender must be an active or deprecated RiskModule
  • payout: must be less than equal to policy.payout.
  • policy: must be a Policy not resolved before and not expired (if payout > 0).

Emits

PolicyResolved
with the payout amount
ERC20-Transfer
to the policyholder with the payout

isActive

function isActive(uint256 policyId) external view returns (bool)

Returns whether a policy is active

A policy is active when it's still in the PolicyPool, not yet resolved or expired. Be aware that a policy might be active but the block.timestamp might be after the expiration date, so it can't be triggered with a payout.

Parameters

Name Type Description
policyId uint256 The id of the policy queried

Return Values

Name Type Description
[0] bool Whether the policy is active or not

getPolicyHash

function getPolicyHash(uint256 policyId) external view returns (bytes32)

Returns the stored hash of the policy

Returns bytes32(0) if the policy isn't active.

Parameters

Name Type Description
policyId uint256 The id of the policy queried

Return Values

Name Type Description
[0] bytes32 Returns the hash of a given policy id

setExposureLimit

function setExposureLimit(contract IRiskModule rm, uint256 newLimit) external

Changes the maximum cumulative loss limit (exposure limit) for a given risk module

This function allows updating the exposure limit for a risk module. The new limit must be greater than or equal to the current active exposure.

Parameters

Name Type Description
rm contract IRiskModule The risk module interface for which to update the exposure limit
newLimit uint256 The new exposure limit to set (will be converted to uint128)

Throws

ExposureLimitExceeded
if the new limit is less than the current active exposure

Emits

ExposureLimitChanged with parameters: (risk module, old limit, new limit)

getExposure

function getExposure(contract IRiskModule rm) external view returns (uint256 active, uint256 limit)

Retrieves the current exposure data for a specific risk module

Returns both the active exposure (current cumulative losses) and the configured exposure limit for the given risk module.

Parameters

Name Type Description
rm contract IRiskModule The risk module interface to query exposure data for

Return Values

Name Type Description
active uint256 The current active exposure (cumulative losses) for the risk module
limit uint256 The configured maximum exposure limit for the risk module

setBaseURI

function setBaseURI(string nftBaseURI_) external

Changes the baseURI of the minted policy NFTs

Emits

BaseURIChanged
With the new and old URIs

Private Functions

__PolicyPool_init_unchained

function __PolicyPool_init_unchained(address treasury_) internal

_authorizeUpgrade

function _authorizeUpgrade(address newImpl) internal view

_setTreasury

function _setTreasury(address treasury_) internal

_componentStatus

function _componentStatus(address component, enum PolicyPool.ComponentKind kind) internal view returns (enum PolicyPool.ComponentStatus)

_requireCompActive

function _requireCompActive(address component, enum PolicyPool.ComponentKind kind) internal view

_requireCompActiveOrDeprecated

function _requireCompActiveOrDeprecated(address component, enum PolicyPool.ComponentKind kind) internal view

_deposit

function _deposit(contract IEToken eToken, uint256 amount, address receiver) internal

_transferIfNonZero

function _transferIfNonZero(address payer, address target, uint256 new_, uint256 old_) internal

_validatePolicy

function _validatePolicy(struct Policy.PolicyData policy) internal view

_resolvePolicy

function _resolvePolicy(struct Policy.PolicyData policy, uint256 payout, bool expired) internal

Internal function that handles the different alternative resolutions for a policy.

Alternatives: with or without payout and expiration.

Parameters

Name Type Description
policy struct Policy.PolicyData A policy created with {Policy-initialize}
payout uint256 The amount to paid to the policyholder
expired bool True for expiration resolution (payout must be 0)

Emits

PolicyResolved
with the payout amount

_changeExposure

function _changeExposure(contract IRiskModule rm, bool increase, uint256 change) internal

_notifyPayout

function _notifyPayout(uint256 policyId, uint256 payout) internal

Notifies the payout with a callback

Only if the policyholder implements the IPolicyHolder interface. Reverts if the policyholder contract explicitly reverts or it doesn't return the IPolicyHolder.onPayoutReceived selector.

_notifyExpiration

function _notifyExpiration(uint256 policyId) internal

Notifies the expiration with a callback

Only if the policyholder implements the IPolicyHolder interface. Never reverts. The onPolicyExpired has a gas limit = HOLDER_GAS_LIMIT

_notifyReplacement

function _notifyReplacement(uint256 oldPolicyId, uint256 newPolicyId) internal

Notifies the replacement with a callback

Only if the policyholder implements the IPolicyHolder interface. Reverts if the policyholder contract explicitly reverts or it doesn't return the IPolicyHolder.onPolicyReplaced selector.

_notifyCancellation

function _notifyCancellation(uint256 cancelledPolicyId, uint256 purePremiumRefund, uint256 jrCocRefund, uint256 srCocRefund) internal

Notifies the cancellation with a callback

Only if the policyholder implements the IPolicyHolder interface. Reverts if the policyholder contract explicitly reverts or it doesn't return the IPolicyHolder.onPolicyCancelled selector.

_baseURI

function _baseURI() internal view virtual returns (string)

Base URI for computing {tokenURI}.

If set, the resulting URI for each token will be the concatenation of the baseURI and the tokenId. Empty by default, can be modified calling {setBaseURI}.

_update

function _update(address to, uint256 tokenId, address auth) internal returns (address)

_Transfers tokenId from its current owner to to, or alternatively mints (or burns) if the current owner (or to) is the zero address. Returns the owner of the tokenId before the update.

The auth argument is optional. If the value passed is non 0, then this function will check that auth is either the owner of the token, or approved to operate on the token (by the owner).

Emits a {Transfer} event.

NOTE: If overriding this function in a way that tracks balances, see also {increaseBalance}.