Skip to content

Commit

Permalink
chore: add support for typed authz grants
Browse files Browse the repository at this point in the history
  • Loading branch information
bangjelkoski committed Nov 21, 2024
1 parent 4f9415b commit 2f93101
Show file tree
Hide file tree
Showing 13 changed files with 419 additions and 9 deletions.
2 changes: 1 addition & 1 deletion packages/sdk-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"@cosmjs/proto-signing": "^0.32.3",
"@cosmjs/stargate": "^0.32.3",
"@ethersproject/bytes": "^5.7.0",
"@injectivelabs/core-proto-ts": "1.13.3",
"@injectivelabs/core-proto-ts": "1.13.4",
"@injectivelabs/exceptions": "^1.14.19",
"@injectivelabs/grpc-web": "^0.0.1",
"@injectivelabs/grpc-web-node-http-transport": "^0.0.2",
Expand Down
3 changes: 2 additions & 1 deletion packages/sdk-ts/src/core/modules/authz/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import MsgGrant from './msgs/MsgGrant.js'
import MsgRevoke from './msgs/MsgRevoke.js'
import MsgAuthzExec from './msgs/MsgExec.js'
import MsgGrantWithAuthorization from './msgs/MsgGrantWithAuthorization.js'

export { MsgGrant, MsgRevoke, MsgAuthzExec }
export { MsgGrant, MsgRevoke, MsgAuthzExec, MsgGrantWithAuthorization }
export * from './utils.js'
export * from './types.js'
4 changes: 1 addition & 3 deletions packages/sdk-ts/src/core/modules/authz/msgs/MsgExec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,7 @@ export default class MsgExec extends MsgBase<
type: 'cosmos-sdk/MsgExec',
value: {
grantee: params.grantee,
msgs: msgs.map((msg) => {
return msg.toEip712()
}),
msgs: msgs.map((msg) => msg.toEip712()),
},
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/sdk-ts/src/core/modules/authz/msgs/MsgGrant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { GeneralException } from '@injectivelabs/exceptions'
import { getGenericAuthorizationFromMessageType } from '../utils.js'
import { GrantAuthorizationType } from './../types.js'

/**
* @deprecated please use MsgGrantWithAuthorization
*/
export declare namespace MsgGrant {
export interface Params {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { MsgBase } from '../../MsgBase.js'
import snakecaseKeys from 'snakecase-keys'
import {
CosmosAuthzV1Beta1Tx,
CosmosAuthzV1Beta1Authz,
GoogleProtobufTimestamp,
} from '@injectivelabs/core-proto-ts'
import { BaseAuthorization } from './grants/Base.js'

export declare namespace MsgGrantWithAuthorization {
export interface Params {
authorization: BaseAuthorization<unknown, unknown>
grantee: string
granter: string
expiration?: number
expiryInYears?: number
expiryInSeconds?: number
}

export type Proto = CosmosAuthzV1Beta1Tx.MsgGrant

export type Object = Omit<CosmosAuthzV1Beta1Tx.MsgGrant, 'msgs'> & {
msgs: any
}
}

/**
* @category Messages
*/
export default class MsgGrantWithAuthorization extends MsgBase<
MsgGrantWithAuthorization.Params,
MsgGrantWithAuthorization.Proto
> {
static fromJSON(
params: MsgGrantWithAuthorization.Params,
): MsgGrantWithAuthorization {
return new MsgGrantWithAuthorization(params)
}

public toProto() {
const { params } = this

const timestamp = this.getTimestamp()
const grant = CosmosAuthzV1Beta1Authz.Grant.create()

grant.authorization = params.authorization.toAny()
grant.expiration = new Date(Number(timestamp.seconds) * 1000)

const message = CosmosAuthzV1Beta1Tx.MsgGrant.create()

message.granter = params.granter
message.grantee = params.grantee
message.grant = grant

return CosmosAuthzV1Beta1Tx.MsgGrant.fromJSON(message)
}

public toData() {
const proto = this.toProto()

return {
'@type': '/cosmos.authz.v1beta1.MsgGrant',
...proto,
}
}

public toAmino() {
const { params } = this

const proto = this.toProto()
const timestamp = this.getTimestamp()
const message = proto

const messageWithAuthorizationType = snakecaseKeys({
...message,
grant: {
authorization: params.authorization.toAmino(),
expiration: new Date(Number(timestamp.seconds) * 1000),
},
})

return {
type: 'cosmos-sdk/MsgGrant',
value:
messageWithAuthorizationType as unknown as MsgGrantWithAuthorization.Object,
}
}

public toDirectSign() {
const proto = this.toProto()

return {
type: '/cosmos.authz.v1beta1.MsgGrant',
message: proto,
}
}

public toWeb3() {
const { params } = this
const amino = this.toAmino()
const timestamp = this.getTimestamp()

const messageWithAuthorizationType = {
granter: amino.value.granter,
grantee: amino.value.grantee,
grant: {
authorization: params.authorization.toWeb3(),
expiration: new Date(Number(timestamp.seconds) * 1000),
},
}

return {
'@type': '/cosmos.authz.v1beta1.MsgGrant',
...messageWithAuthorizationType,
}
}

private getTimestamp() {
const { params } = this

if (params.expiration) {
const timestamp = GoogleProtobufTimestamp.Timestamp.create()

timestamp.seconds = params.expiration.toString()

return timestamp
}

const defaultExpiryYears = params.expiryInSeconds ? 0 : 5
const dateNow = new Date()
const expiration = new Date(
dateNow.getFullYear() + (params.expiryInYears || defaultExpiryYears),
dateNow.getMonth(),
dateNow.getDate(),
)

const timestamp = GoogleProtobufTimestamp.Timestamp.create()

const timestampInSeconds = (
expiration.getTime() / 1000 +
(params.expiryInSeconds || 0)
).toString()

timestamp.seconds = timestampInSeconds

return timestamp
}

public toBinary(): Uint8Array {
return CosmosAuthzV1Beta1Tx.MsgGrant.encode(this.toProto()).finish()
}
}
15 changes: 15 additions & 0 deletions packages/sdk-ts/src/core/modules/authz/msgs/grants/Base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { GoogleProtobufAny } from '@injectivelabs/core-proto-ts'

export abstract class BaseAuthorization<Params, DataRepresentation> {
params: Params

constructor(params: Params) {
this.params = params
}

public abstract toAny(): GoogleProtobufAny.Any

public abstract toAmino(): DataRepresentation

public abstract toWeb3(): DataRepresentation
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import {
GoogleProtobufAny,
CosmwasmWasmV1Authz,
} from '@injectivelabs/core-proto-ts'
import { BaseAuthorization } from './Base.js'

export declare namespace ContractExecutionAuthorization {
export interface Params {
contract: string
limit?: {
maxCalls: number
}
filter?: {
acceptedMessagesKeys: string[]
}
}

export type Any = GoogleProtobufAny.Any

export type Amino = Object
}

/**
* @category Contract Exec Arguments
*/
export default class ContractExecutionAuthorization extends BaseAuthorization<
ContractExecutionAuthorization.Params,
ContractExecutionAuthorization.Amino
> {
static fromJSON(
params: ContractExecutionAuthorization.Params,
): ContractExecutionAuthorization {
return new ContractExecutionAuthorization(params)
}

public toAny(): GoogleProtobufAny.Any {
const { params } = this

const authorization =
CosmwasmWasmV1Authz.ContractExecutionAuthorization.create()
const grant = CosmwasmWasmV1Authz.ContractGrant.create()

grant.contract = params.contract

if (params.limit) {
const limit = CosmwasmWasmV1Authz.MaxCallsLimit.create()

limit.remaining = params.limit.maxCalls.toString()

const any = GoogleProtobufAny.Any.create()
any.typeUrl = '/cosmwasm.wasm.v1.MaxCallsLimit'
any.value = CosmwasmWasmV1Authz.MaxCallsLimit.encode(limit).finish()

grant.limit = any
}

if (params.filter) {
const filter = CosmwasmWasmV1Authz.AcceptedMessageKeysFilter.create()

filter.keys = params.filter.acceptedMessagesKeys

const any = GoogleProtobufAny.Any.create()
any.typeUrl = '/cosmwasm.wasm.v1.AcceptedMessageKeysFilter'
any.value =
CosmwasmWasmV1Authz.AcceptedMessageKeysFilter.encode(filter).finish()

grant.limit = any
}

authorization.grants = [grant]

const any = GoogleProtobufAny.Any.create()
any.typeUrl = '/cosmwasm.wasm.v1.ContractExecutionAuthorization'
any.value =
CosmwasmWasmV1Authz.ContractExecutionAuthorization.encode(
authorization,
).finish()

return any
}

public toAmino(): ContractExecutionAuthorization.Amino {
const { params } = this

const grant = {} as Record<string, any>

grant.contract = params.contract

if (params.limit) {
grant.limit = {
type: 'wasm/MaxCallsLimit',
remaining: params.limit.maxCalls,
}
}

if (params.filter) {
grant.filter = {
type: 'wasm/AcceptedMessageKeysFilter',
keys: params.filter.acceptedMessagesKeys,
}
}

return {
type: 'wasm/ContractExecutionAuthorization',
grants: [grant],
}
}

public toWeb3(): ContractExecutionAuthorization.Amino {
const { params } = this

const grant = {} as Record<string, any>

grant.contract = params.contract

if (params.limit) {
grant.limit = {
'@type': '/cosmwasm.wasm.v1.MaxCallsLimit',
remaining: params.limit.maxCalls,
}
}

if (params.filter) {
grant.filter = {
'@type': '/cosmwasm.wasm.v1.AcceptedMessageKeysFilter',
keys: params.filter.acceptedMessagesKeys,
}
}

return {
'@type': '/cosmwasm.wasm.v1.ContractExecutionAuthorization',
grants: [grant],
}
}
}
Loading

0 comments on commit 2f93101

Please sign in to comment.