wasm

package
v0.50.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 23, 2023 License: Apache-2.0 Imports: 33 Imported by: 0

README

Wasm Module

This should be a brief overview of the functionality

Configuration

You can add the following section to config/app.toml:

[wasm]
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
query_gas_limit = 300000
# This defines the memory size for Wasm modules that we can keep cached to speed-up instantiation
# The value is in MiB not bytes
memory_cache_size = 300

The values can also be set via CLI flags on with the start command:

--wasm.memory_cache_size uint32     Sets the size in MiB (NOT bytes) of an in-memory cache for wasm modules. Set to 0 to disable. (default 100)
--wasm.query_gas_limit uint         Set the max gas that can be spent on executing a query with a Wasm contract (default 3000000)

Events

A number of events are returned to allow good indexing of the transactions from smart contracts.

Every call to Instantiate or Execute will be tagged with the info on the contract that was executed and who executed it. It should look something like this (with different addresses). The module is always wasm, and code_id is only present when Instantiating a contract, so you can subscribe to new instances, it is omitted on Execute. There is also an action tag which is auto-added by the Cosmos SDK and has a value of either store-code, instantiate or execute depending on which message was sent:

{
    "Type": "message",
    "Attr": [
        {
            "key": "module",
            "value": "wasm"
        },
        {
            "key": "action",
            "value": "instantiate"
        },
        {
            "key": "signer",
            "value": "cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"
        },
        {
            "key": "code_id",
            "value": "1"
        },
        {
            "key": "_contract_address",
            "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
        }
    ]
}

If any funds were transferred to the contract as part of the message, or if the contract released funds as part of it's executions, it will receive the typical events associated with sending tokens from bank. In this case, we instantiate the contract and provide a initial balance in the same MsgInstantiateContract. We see the following events in addition to the above one:

[
    {
        "Type": "transfer",
        "Attr": [
            {
                "key": "recipient",
                "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
            },
            {
                "key": "sender",
                "value": "cosmos1ffnqn02ft2psvyv4dyr56nnv6plllf9pm2kpmv"
            },
            {
                "key": "amount",
                "value": "100000denom"
            }
        ]
    }
]

Finally, the contract itself can emit a "custom event" on Execute only (not on Init). There is one event per contract, so if one contract calls a second contract, you may receive one event for the original contract and one for the re-invoked contract. All attributes from the contract are passed through verbatim, and we add a _contract_address attribute that contains the actual contract that emitted that event. Here is an example from the escrow contract successfully releasing funds to the destination address:

{
    "Type": "wasm",
    "Attr": [
        {
            "key": "_contract_address",
            "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
        },
        {
            "key": "action",
            "value": "release"
        },
        {
            "key": "destination",
            "value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq"
        }
    ]
}
Pulling this all together

We will invoke an escrow contract to release to the designated beneficiary. The escrow was previously loaded with 100000denom (from the above example). In this transaction, we send 5000denom along with the MsgExecuteContract and the contract releases the entire funds (105000denom) to the beneficiary.

We will see all the following events, where you should be able to reconstruct the actions (remember there are two events for each transfer). We see (1) the initial transfer of funds to the contract, (2) the contract custom event that it released funds (3) the transfer of funds from the contract to the beneficiary and (4) the generic x/wasm event stating that the contract was executed (which always appears, while 2 is optional and has information as reliable as the contract):

[
    {
        "Type": "transfer",
        "Attr": [
            {
                "key": "recipient",
                "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
            },
            {
                "key": "sender",
                "value": "cosmos1zm074khx32hqy20hlshlsd423n07pwlu9cpt37"
            },
            {
                "key": "amount",
                "value": "5000denom"
            }
        ]
    },
    {
        "Type": "wasm",
        "Attr": [
            {
                "key": "_contract_address",
                "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
            },
            {
                "key": "action",
                "value": "release"
            },
            {
                "key": "destination",
                "value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq"
            }
        ]
    },
    {
        "Type": "transfer",
        "Attr": [
            {
                "key": "recipient",
                "value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq"
            },
            {
                "key": "sender",
                "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
            },
            {
                "key": "amount",
                "value": "105000denom"
            }
        ]
    },
    {
        "Type": "message",
        "Attr": [
            {
                "key": "module",
                "value": "wasm"
            },
            {
                "key": "action",
                "value": "execute"
            },
            {
                "key": "signer",
                "value": "cosmos1zm074khx32hqy20hlshlsd423n07pwlu9cpt37"
            },
            {
                "key": "_contract_address",
                "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
            }
        ]
    }
]

A note on this format. This is what we return from our module. However, it seems to me that many events with the same Type get merged together somewhere along the stack, so in this case, you may end up with one "transfer" event with the info for both transfers. Double check when evaluating the event logs, I will document better with more experience, especially when I find out the entire path for the events.

Messages

TODO

CLI

TODO - working, but not the nicest interface (json + bash = bleh). Use to upload, but I suggest to focus on frontend / js tooling

Rest

TODO - main supported interface, under rapid change

Documentation

Overview

autogenerated code using github.com/rigelrozanski/multitool aliases generated for the following subdirectories: ALIASGEN: github.com/Cosmwasm/wasmd/x/wasm/types ALIASGEN: github.com/CosmWasm/wasmd/x/wasm/keeper

Index

Constants

View Source
const (
	// Deprecated: Do not use.
	ModuleName = types.ModuleName
	// Deprecated: Do not use.
	StoreKey = types.StoreKey
	// Deprecated: Do not use.
	TStoreKey = types.TStoreKey
	// Deprecated: Do not use.
	QuerierRoute = types.QuerierRoute
	// Deprecated: Do not use.
	RouterKey = types.RouterKey
	// Deprecated: Do not use.
	WasmModuleEventType = types.WasmModuleEventType
	// Deprecated: Do not use.
	AttributeKeyContractAddr = types.AttributeKeyContractAddr
)

Variables

View Source
var (
	// functions aliases
	// Deprecated: Do not use.
	RegisterCodec = types.RegisterLegacyAminoCodec
	// Deprecated: Do not use.
	RegisterInterfaces = types.RegisterInterfaces
	// Deprecated: Do not use.
	ValidateGenesis = types.ValidateGenesis
	// Deprecated: Do not use.
	GetCodeKey = types.GetCodeKey
	// Deprecated: Do not use.
	GetContractAddressKey = types.GetContractAddressKey
	// Deprecated: Do not use.
	GetContractStorePrefixKey = types.GetContractStorePrefix
	// Deprecated: Do not use.
	NewCodeInfo = types.NewCodeInfo
	// Deprecated: Do not use.
	NewAbsoluteTxPosition = types.NewAbsoluteTxPosition
	// Deprecated: Do not use.
	NewContractInfo = types.NewContractInfo
	// Deprecated: Do not use.
	NewEnv = types.NewEnv
	// Deprecated: Do not use.
	NewWasmCoins = types.NewWasmCoins
	// Deprecated: Do not use.
	DefaultWasmConfig = types.DefaultWasmConfig
	// Deprecated: Do not use.
	DefaultParams = types.DefaultParams
	// Deprecated: Do not use.
	InitGenesis = keeper.InitGenesis
	// Deprecated: Do not use.
	ExportGenesis = keeper.ExportGenesis
	// Deprecated: Do not use.
	NewMessageHandler = keeper.NewDefaultMessageHandler
	// Deprecated: Do not use.
	DefaultEncoders = keeper.DefaultEncoders
	// Deprecated: Do not use.
	EncodeBankMsg = keeper.EncodeBankMsg
	// Deprecated: Do not use.
	NoCustomMsg = keeper.NoCustomMsg
	// Deprecated: Do not use.
	EncodeStakingMsg = keeper.EncodeStakingMsg
	// Deprecated: Do not use.
	EncodeWasmMsg = keeper.EncodeWasmMsg
	// Deprecated: Do not use.
	NewKeeper = keeper.NewKeeper
	// Deprecated: Do not use.
	DefaultQueryPlugins = keeper.DefaultQueryPlugins
	// Deprecated: Do not use.
	BankQuerier = keeper.BankQuerier
	// Deprecated: Do not use.
	NoCustomQuerier = keeper.NoCustomQuerier
	// Deprecated: Do not use.
	StakingQuerier = keeper.StakingQuerier
	// Deprecated: Do not use.
	WasmQuerier = keeper.WasmQuerier
	// Deprecated: Do not use.
	CreateTestInput = keeper.CreateTestInput
	// Deprecated: Do not use.
	TestHandler = keeper.TestHandler
	// Deprecated: Do not use.
	NewQuerier = keeper.Querier
	// Deprecated: Do not use.
	ContractFromPortID = keeper.ContractFromPortID
	// Deprecated: Do not use.
	WithWasmEngine = keeper.WithWasmEngine
	// Deprecated: Do not use.
	NewCountTXDecorator = keeper.NewCountTXDecorator

	// variable aliases
	// Deprecated: Do not use.
	DefaultCodespace = types.DefaultCodespace
	// Deprecated: Do not use.
	ErrCreateFailed = types.ErrCreateFailed
	// Deprecated: Do not use.
	ErrAccountExists = types.ErrAccountExists
	// Deprecated: Do not use.
	ErrInstantiateFailed = types.ErrInstantiateFailed
	// Deprecated: Do not use.
	ErrExecuteFailed = types.ErrExecuteFailed
	// Deprecated: Do not use.
	ErrGasLimit = types.ErrGasLimit
	// Deprecated: Do not use.
	ErrInvalidGenesis = types.ErrInvalidGenesis
	// Deprecated: Do not use.
	ErrNotFound = types.ErrNotFound
	// Deprecated: Do not use.
	ErrQueryFailed = types.ErrQueryFailed
	// Deprecated: Do not use.
	ErrInvalidMsg = types.ErrInvalidMsg
	// Deprecated: Do not use.
	KeyLastCodeID = types.KeySequenceCodeID
	// Deprecated: Do not use.
	KeyLastInstanceID = types.KeySequenceInstanceID
	// Deprecated: Do not use.
	CodeKeyPrefix = types.CodeKeyPrefix
	// Deprecated: Do not use.
	ContractKeyPrefix = types.ContractKeyPrefix
	// Deprecated: Do not use.
	ContractStorePrefix = types.ContractStorePrefix
)

Functions

func AddModuleInitFlags added in v0.12.0

func AddModuleInitFlags(startCmd *cobra.Command)

AddModuleInitFlags implements servertypes.ModuleInitFlags interface.

func CheckLibwasmVersion added in v0.32.0

func CheckLibwasmVersion(wasmExpectedVersion string) error

CheckLibwasmVersion ensures that the libwasmvm version loaded at runtime matches the version of the github.com/CosmWasm/wasmvm dependency in go.mod. This us useful when dealing with shared libraries that are copied or moved from their default location, e.g. when building the node on one machine and deploying it to other machines.

Usually the libwasmvm version (the Rust project) and wasmvm version (the Go project) match. However, there are situations in which this is not the case. This can be during development or if one of the two is patched. In such cases it is advised to not execute the check.

An alternative method to obtain the libwasmvm version loaded at runtime is executing `wasmd query wasm libwasmvm-version`.

func ReadWasmConfig added in v0.12.0

func ReadWasmConfig(opts servertypes.AppOptions) (types.WasmConfig, error)

ReadWasmConfig reads the wasm specifig configuration

func ValidateChannelParams added in v0.16.0

func ValidateChannelParams(channelID string) error

Types

type AppModule

type AppModule struct {
	AppModuleBasic
	// contains filtered or unexported fields
}

AppModule implements an application module for the wasm module.

func NewAppModule

func NewAppModule(
	cdc codec.Codec,
	keeper *keeper.Keeper,
	validatorSetSource keeper.ValidatorSetSource,
	ak types.AccountKeeper,
	bk simulation.BankKeeper,
	router *baseapp.MsgServiceRouter,
	ss exported.Subspace,
) AppModule

NewAppModule creates a new AppModule object

func (AppModule) ConsensusVersion added in v0.22.0

func (AppModule) ConsensusVersion() uint64

ConsensusVersion is a sequence number for state-breaking change of the module. It should be incremented on each consensus-breaking change introduced by the module. To avoid wrong/empty versions, the initial version should be set to 1.

func (AppModule) ExportGenesis

func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage

ExportGenesis returns the exported genesis state as raw bytes for the wasm module.

func (AppModule) GenerateGenesisState added in v0.12.0

func (AppModule) GenerateGenesisState(simState *module.SimulationState)

GenerateGenesisState creates a randomized GenState of the bank module.

func (AppModule) InitGenesis

func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate

InitGenesis performs genesis initialization for the wasm module. It returns no validator updates.

func (AppModule) IsAppModule added in v0.40.0

func (am AppModule) IsAppModule()

IsAppModule implements the appmodule.AppModule interface.

func (AppModule) IsOnePerModuleType added in v0.40.0

func (am AppModule) IsOnePerModuleType()

IsOnePerModuleType implements the depinject.OnePerModuleType interface.

func (AppModule) ProposalMsgs added in v0.40.0

func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg

ProposalMsgs returns msgs used for governance proposals for simulations.

func (AppModule) QuerierRoute

func (AppModule) QuerierRoute() string

QuerierRoute returns the wasm module's querier route name.

func (AppModule) RegisterInvariants

func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry)

RegisterInvariants registers the wasm module invariants.

func (AppModule) RegisterServices added in v0.12.0

func (am AppModule) RegisterServices(cfg module.Configurator)

func (AppModule) RegisterStoreDecoder added in v0.12.0

func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry)

RegisterStoreDecoder registers a decoder for supply module's types

func (AppModule) WeightedOperations added in v0.12.0

func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation

WeightedOperations returns the all the gov module operations with their respective weights.

type AppModuleBasic

type AppModuleBasic struct{}

AppModuleBasic defines the basic application module used by the wasm module.

func (AppModuleBasic) DefaultGenesis

func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage

DefaultGenesis returns default genesis state as raw bytes for the wasm module.

func (AppModuleBasic) GetQueryCmd

func (b AppModuleBasic) GetQueryCmd() *cobra.Command

GetQueryCmd returns no root query command for the wasm module.

func (AppModuleBasic) GetTxCmd

func (b AppModuleBasic) GetTxCmd() *cobra.Command

GetTxCmd returns the root tx command for the wasm module.

func (AppModuleBasic) Name

func (AppModuleBasic) Name() string

Name returns the wasm module's name.

func (AppModuleBasic) RegisterGRPCGatewayRoutes added in v0.12.0

func (b AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, serveMux *runtime.ServeMux)

func (AppModuleBasic) RegisterInterfaces added in v0.12.0

func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry)

RegisterInterfaces implements InterfaceModule

func (AppModuleBasic) RegisterLegacyAminoCodec added in v0.12.0

func (b AppModuleBasic) RegisterLegacyAminoCodec(amino *codec.LegacyAmino)

func (AppModuleBasic) ValidateGenesis

func (b AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, _ client.TxEncodingConfig, message json.RawMessage) error

ValidateGenesis performs genesis state validation for the wasm module.

type BankEncoder deprecated

type BankEncoder = keeper.BankEncoder

Deprecated: Do not use.

type Code deprecated

type Code = types.Code

Deprecated: Do not use.

type CodeInfo deprecated

type CodeInfo = types.CodeInfo

Deprecated: Do not use.

type CodeInfoResponse deprecated added in v0.12.0

type CodeInfoResponse = types.CodeInfoResponse

Deprecated: Do not use.

type Config deprecated added in v0.11.0

type Config = types.WasmConfig

Deprecated: Do not use.

type Contract deprecated

type Contract = types.Contract

Deprecated: Do not use.

type ContractInfo deprecated

type ContractInfo = types.ContractInfo

Deprecated: Do not use.

type CreatedAt deprecated

type CreatedAt = types.AbsoluteTxPosition

Deprecated: Do not use.

type CustomEncoder deprecated

type CustomEncoder = keeper.CustomEncoder

Deprecated: Do not use.

type CustomQuerier deprecated

type CustomQuerier = keeper.CustomQuerier

Deprecated: Do not use.

type GenesisState deprecated

type GenesisState = types.GenesisState

Deprecated: Do not use.

type IBCHandler added in v0.16.0

type IBCHandler struct {
	// contains filtered or unexported fields
}

func NewIBCHandler added in v0.16.0

func NewIBCHandler(k types.IBCContractKeeper, ck types.ChannelKeeper, vg appVersionGetter) IBCHandler

func (IBCHandler) OnAcknowledgementPacket added in v0.16.0

func (i IBCHandler) OnAcknowledgementPacket(
	ctx sdk.Context,
	packet channeltypes.Packet,
	acknowledgement []byte,
	relayer sdk.AccAddress,
) error

OnAcknowledgementPacket implements the IBCModule interface

func (IBCHandler) OnChanCloseConfirm added in v0.16.0

func (i IBCHandler) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error

OnChanCloseConfirm implements the IBCModule interface

func (IBCHandler) OnChanCloseInit added in v0.16.0

func (i IBCHandler) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error

OnChanCloseInit implements the IBCModule interface

func (IBCHandler) OnChanOpenAck added in v0.16.0

func (i IBCHandler) OnChanOpenAck(
	ctx sdk.Context,
	portID, channelID string,
	counterpartyChannelID string,
	counterpartyVersion string,
) error

OnChanOpenAck implements the IBCModule interface

func (IBCHandler) OnChanOpenConfirm added in v0.16.0

func (i IBCHandler) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error

OnChanOpenConfirm implements the IBCModule interface

func (IBCHandler) OnChanOpenInit added in v0.16.0

func (i IBCHandler) OnChanOpenInit(
	ctx sdk.Context,
	order channeltypes.Order,
	connectionHops []string,
	portID string,
	channelID string,
	chanCap *capabilitytypes.Capability,
	counterParty channeltypes.Counterparty,
	version string,
) (string, error)

OnChanOpenInit implements the IBCModule interface

func (IBCHandler) OnChanOpenTry added in v0.16.0

func (i IBCHandler) OnChanOpenTry(
	ctx sdk.Context,
	order channeltypes.Order,
	connectionHops []string,
	portID, channelID string,
	chanCap *capabilitytypes.Capability,
	counterParty channeltypes.Counterparty,
	counterpartyVersion string,
) (string, error)

OnChanOpenTry implements the IBCModule interface

func (IBCHandler) OnRecvPacket added in v0.16.0

func (i IBCHandler) OnRecvPacket(
	ctx sdk.Context,
	packet channeltypes.Packet,
	relayer sdk.AccAddress,
) ibcexported.Acknowledgement

OnRecvPacket implements the IBCModule interface

func (IBCHandler) OnTimeoutPacket added in v0.16.0

func (i IBCHandler) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error

OnTimeoutPacket implements the IBCModule interface

type Keeper deprecated

type Keeper = keeper.Keeper

Deprecated: Do not use.

type MessageEncoders deprecated

type MessageEncoders = keeper.MessageEncoders

Deprecated: Do not use.

type MessageHandler deprecated

type MessageHandler = keeper.SDKMessageHandler

Deprecated: Do not use.

type Model deprecated

type Model = types.Model

Deprecated: Do not use.

type MsgClearAdmin deprecated added in v0.9.0

type MsgClearAdmin = types.MsgClearAdmin

Deprecated: Do not use.

type MsgClearAdminResponse deprecated added in v0.14.1

type MsgClearAdminResponse = types.MsgClearAdminResponse

Deprecated: Do not use.

type MsgExecuteContract deprecated

type MsgExecuteContract = types.MsgExecuteContract

Deprecated: Do not use.

type MsgExecuteContractResponse deprecated added in v0.14.1

type MsgExecuteContractResponse = types.MsgExecuteContractResponse

Deprecated: Do not use.

type MsgInstantiateContract deprecated

type MsgInstantiateContract = types.MsgInstantiateContract

Deprecated: Do not use.

type MsgInstantiateContract2 deprecated added in v0.29.0

type MsgInstantiateContract2 = types.MsgInstantiateContract2

Deprecated: Do not use.

type MsgInstantiateContractResponse deprecated added in v0.14.1

type MsgInstantiateContractResponse = types.MsgInstantiateContractResponse

Deprecated: Do not use.

type MsgMigrateContract deprecated added in v0.9.0

type MsgMigrateContract = types.MsgMigrateContract

Deprecated: Do not use.

type MsgMigrateContractResponse deprecated added in v0.14.1

type MsgMigrateContractResponse = types.MsgMigrateContractResponse

Deprecated: Do not use.

type MsgServer deprecated added in v0.14.1

type MsgServer = types.MsgServer

Deprecated: Do not use.

type MsgStoreCode deprecated

type MsgStoreCode = types.MsgStoreCode

Deprecated: Do not use.

type MsgStoreCodeResponse deprecated added in v0.14.1

type MsgStoreCodeResponse = types.MsgStoreCodeResponse

Deprecated: Do not use.

type MsgUpdateAdmin deprecated added in v0.9.0

type MsgUpdateAdmin = types.MsgUpdateAdmin

Deprecated: Do not use.

type MsgUpdateAdminResponse deprecated added in v0.14.1

type MsgUpdateAdminResponse = types.MsgUpdateAdminResponse

Deprecated: Do not use.

type MsgWasmIBCCall deprecated added in v0.16.0

type MsgWasmIBCCall = types.MsgIBCSend

Deprecated: Do not use.

type Option deprecated added in v0.16.0

type Option = keeper.Option

Deprecated: Do not use.

type QueryHandler deprecated

type QueryHandler = keeper.QueryHandler

Deprecated: Do not use.

type QueryPlugins deprecated

type QueryPlugins = keeper.QueryPlugins

Deprecated: Do not use.

type StakingEncoder deprecated

type StakingEncoder = keeper.StakingEncoder

Deprecated: Do not use.

type WasmEncoder deprecated

type WasmEncoder = keeper.WasmEncoder

Deprecated: Do not use.

Directories

Path Synopsis
client
cli
migrations
v1
v2
NOTE: Usage of x/params to manage parameters is deprecated in favor of x/gov controlled execution of MsgUpdateParams messages.
NOTE: Usage of x/params to manage parameters is deprecated in favor of x/gov controlled execution of MsgUpdateParams messages.
v3
Package types is a reverse proxy.
Package types is a reverse proxy.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL