@safe-global/safe-apps-sdk
Advanced tools
Comparing version 7.9.0 to 7.10.0
# @gnosis.pm/safe-apps-sdk | ||
## 7.10.0 | ||
### Minor Changes | ||
- f89c36f: Adds the new `setSafeSettings` and `getOffChainSignature` methods. | ||
## 7.9.0 | ||
@@ -4,0 +10,0 @@ |
{ | ||
"name": "@safe-global/safe-apps-sdk", | ||
"version": "7.9.0", | ||
"version": "7.10.0", | ||
"description": "SDK developed to integrate third-party apps with Safe app.", | ||
@@ -5,0 +5,0 @@ "main": "dist/src/index.js", |
@@ -11,2 +11,3 @@ export declare enum Methods { | ||
getEnvironmentInfo = "getEnvironmentInfo", | ||
getOffChainSignature = "getOffChainSignature", | ||
requestAddressBook = "requestAddressBook", | ||
@@ -13,0 +14,0 @@ wallet_getPermissions = "wallet_getPermissions", |
@@ -15,2 +15,3 @@ "use strict"; | ||
Methods["getEnvironmentInfo"] = "getEnvironmentInfo"; | ||
Methods["getOffChainSignature"] = "getOffChainSignature"; | ||
Methods["requestAddressBook"] = "requestAddressBook"; | ||
@@ -17,0 +18,0 @@ Methods["wallet_getPermissions"] = "wallet_getPermissions"; |
@@ -14,2 +14,3 @@ export declare const RPC_CALLS: { | ||
readonly eth_estimateGas: "eth_estimateGas"; | ||
readonly safe_setSettings: "safe_setSettings"; | ||
}; |
@@ -17,3 +17,4 @@ "use strict"; | ||
eth_estimateGas: 'eth_estimateGas', | ||
safe_setSettings: 'safe_setSettings', | ||
}; | ||
//# sourceMappingURL=constants.js.map |
@@ -1,2 +0,2 @@ | ||
import { BlockNumberArg, Communicator, Log, BlockTransactionString, BlockTransactionObject, Web3TransactionObject, TransactionConfig, Web3TransactionReceiptObject, PastLogsOptions } from '../types'; | ||
import { BlockNumberArg, Communicator, Log, BlockTransactionString, BlockTransactionObject, Web3TransactionObject, TransactionConfig, Web3TransactionReceiptObject, PastLogsOptions, SafeSettings } from '../types'; | ||
declare class Eth { | ||
@@ -15,2 +15,3 @@ call: (params?: [TransactionConfig, (string | undefined)?] | undefined) => Promise<string>; | ||
getEstimateGas: (transaction: TransactionConfig) => Promise<number>; | ||
setSafeSettings: (params?: [SafeSettings] | undefined) => Promise<SafeSettings>; | ||
private readonly communicator; | ||
@@ -17,0 +18,0 @@ constructor(communicator: Communicator); |
@@ -57,2 +57,5 @@ "use strict"; | ||
})([transaction]); | ||
this.setSafeSettings = this.buildRequest({ | ||
call: constants_1.RPC_CALLS.safe_setSettings, | ||
}); | ||
} | ||
@@ -59,0 +62,0 @@ buildRequest(args) { |
@@ -12,2 +12,3 @@ import { Communicator, SafeInfo, ChainInfo, SafeBalances, GetBalanceParams, EnvironmentInfo, AddressBookItem, EIP712TypedData } from '../types'; | ||
calculateTypedMessageHash(typedMessage: EIP712TypedData): string; | ||
getOffChainSignature(messageHash: string): Promise<string>; | ||
isMessageSigned(message: string | EIP712TypedData, signature?: string): Promise<boolean>; | ||
@@ -14,0 +15,0 @@ isMessageHashSigned(messageHash: string, signature?: string): Promise<boolean>; |
@@ -93,2 +93,6 @@ "use strict"; | ||
} | ||
async getOffChainSignature(messageHash) { | ||
const response = await this.communicator.send(methods_1.Methods.getOffChainSignature, messageHash); | ||
return response.data; | ||
} | ||
async isMessageSigned(message, signature = '0x') { | ||
@@ -95,0 +99,0 @@ let check; |
@@ -1,2 +0,2 @@ | ||
import { GatewayTransactionDetails, SendTransactionsParams, Communicator, SendTransactionsResponse, EIP712TypedData } from '../types'; | ||
import { GatewayTransactionDetails, SendTransactionsParams, Communicator, SendTransactionsResponse, EIP712TypedData, SignMessageResponse } from '../types'; | ||
declare class TXs { | ||
@@ -6,6 +6,6 @@ private readonly communicator; | ||
getBySafeTxHash(safeTxHash: string): Promise<GatewayTransactionDetails>; | ||
signMessage(message: string): Promise<SendTransactionsResponse>; | ||
signTypedMessage(typedData: EIP712TypedData): Promise<SendTransactionsResponse>; | ||
signMessage(message: string): Promise<SignMessageResponse>; | ||
signTypedMessage(typedData: EIP712TypedData): Promise<SignMessageResponse>; | ||
send({ txs, params }: SendTransactionsParams): Promise<SendTransactionsResponse>; | ||
} | ||
export { TXs }; |
@@ -17,2 +17,3 @@ import { Methods } from '../communication/methods'; | ||
[Methods.getEnvironmentInfo]: EnvironmentInfo; | ||
[Methods.getOffChainSignature]: string; | ||
[Methods.requestAddressBook]: AddressBookItem[]; | ||
@@ -19,0 +20,0 @@ [Methods.wallet_getPermissions]: Permission[]; |
@@ -88,1 +88,4 @@ import { RPC_CALLS } from '../eth/constants'; | ||
} | ||
export interface SafeSettings { | ||
offChainSigning?: boolean; | ||
} |
@@ -51,2 +51,6 @@ import { ChainInfo as _ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'; | ||
}; | ||
export type OffChainSignMessageResponse = { | ||
messageHash: string; | ||
}; | ||
export type SignMessageResponse = SendTransactionsResponse | OffChainSignMessageResponse; | ||
export type SafeInfo = { | ||
@@ -53,0 +57,0 @@ safeAddress: string; |
{ | ||
"name": "@safe-global/safe-apps-sdk", | ||
"version": "7.9.0", | ||
"version": "7.10.0", | ||
"description": "SDK developed to integrate third-party apps with Safe app.", | ||
@@ -5,0 +5,0 @@ "main": "dist/src/index.js", |
@@ -44,3 +44,3 @@ # Safe Apps SDK | ||
This library exposes a class as a default export. It accepts an optional options object: | ||
`allowedDomains` - Array of regular expressions for origins to accept messages from. If not passed, accepts | ||
`allowedDomains` - Array of regular expressions for origins to accept messages from. If not passed, accepts | ||
messages from all domains | ||
@@ -175,2 +175,42 @@ `debug` - Boolean. If enabled, it will log outgoing/incoming messages. | ||
#### Off-chain signing | ||
Signing a message off-chain first requires dispatching a `safe_setSettings` RPC call (via `sdk.eth.setSafeSettings()`) with the `offChainSigning` flag set to `true`. Then the relevant `signMessage`/`signTypedData` needs to be called, proposing a message to our services that can then be approved by Safe owners. | ||
```js | ||
const settings = { | ||
offChainSigning: true, | ||
}; | ||
const currentSettings = await appsSdk.eth.setSafeSettings([settings]); | ||
const message = "I'm the owner of wallet 0x000000"; | ||
const hash = await sdk.txs.signMessage(message); | ||
// { messageHash: '0x...' } | ||
const typedMessage = { | ||
... | ||
} | ||
const hash = await sdk.txs.signTypedMessage(typedMessage); | ||
// { messageHash: '0x...' } | ||
``` | ||
Signing returns the `messageHash` of the proposed [`SafeMessage`](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol#L12) which can be used to fetch the off-chain signature with. | ||
```js | ||
const offChainSignature = await sdk.safe.getOffChainSignature(messageHash); | ||
// '0x123' | ||
``` | ||
The returned signature will either be an empty string or valid one once the required number of Safe owners have confirmed the message. | ||
To validate the signature, use `sdk.safe.isMessageSigned()`, passing the signature as the second argument. | ||
```js | ||
const message = "I'm the owner of wallet 0x000000"; | ||
const messageIsSigned = await sdk.safe.isMessageSigned(message, signature); | ||
``` | ||
#### On-chain signing | ||
Because the Safe is a smart contract wallet, it doesn't have a private key that the wallet can use to sign messages. Instead, we have a library to sign messages, and the validation logic follows [EIP-1271 - Standard Signature Validation Method for Contracts](https://eips.ethereum.org/EIPS/eip-1271). Signing a message with the Safe requires sending a Safe transaction that needs to be approved by Safe owners. To dive into the smart contract implementation, you can start with [library tests](https://github.com/safe-global/safe-contracts/blob/ee92957307653ae6cf7312bbcb1a13c6884ea6ea/test/libraries/SignMessageLib.spec.ts) in the safe-contracts repo. | ||
@@ -420,2 +460,16 @@ | ||
### setSafeSettings | ||
Sets settings of the currently opened Safe. | ||
> Note: Returns the new `SafeSettings`. | ||
```js | ||
const settings = { | ||
offChainSigning: true, | ||
}; | ||
const success = await appsSdk.eth.setSafeSettings([settings]); | ||
``` | ||
## Testing in the Safe application | ||
@@ -422,0 +476,0 @@ |
@@ -11,2 +11,3 @@ export enum Methods { | ||
getEnvironmentInfo = 'getEnvironmentInfo', | ||
getOffChainSignature = 'getOffChainSignature', | ||
requestAddressBook = 'requestAddressBook', | ||
@@ -13,0 +14,0 @@ wallet_getPermissions = 'wallet_getPermissions', |
@@ -14,2 +14,3 @@ export const RPC_CALLS = { | ||
eth_estimateGas: 'eth_estimateGas', | ||
safe_setSettings: 'safe_setSettings', | ||
} as const; |
@@ -354,2 +354,23 @@ import SDK from '../index'; | ||
}); | ||
describe('setSafeSettings', () => { | ||
it('Should send valid, Safe-specific settings to the interface', () => { | ||
sdkInstance.eth.setSafeSettings([ | ||
{ | ||
offChainSigning: true, | ||
}, | ||
]); | ||
expect(spy).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
method: Methods.rpcCall, | ||
params: { | ||
call: 'safe_setSettings', | ||
params: [{ offChainSigning: true }], | ||
}, | ||
}), | ||
'*', | ||
); | ||
}); | ||
}); | ||
}); |
@@ -14,2 +14,3 @@ import { RPC_CALLS } from '../eth/constants'; | ||
PastLogsOptions, | ||
SafeSettings, | ||
} from '../types'; | ||
@@ -46,2 +47,3 @@ import { Methods } from '../communication/methods'; | ||
public getEstimateGas; | ||
public setSafeSettings; | ||
@@ -99,2 +101,5 @@ private readonly communicator: Communicator; | ||
})([transaction]); | ||
this.setSafeSettings = this.buildRequest<[SafeSettings], SafeSettings>({ | ||
call: RPC_CALLS.safe_setSettings, | ||
}); | ||
} | ||
@@ -101,0 +106,0 @@ |
@@ -127,2 +127,11 @@ import { ethers } from 'ethers'; | ||
async getOffChainSignature(messageHash: string): Promise<string> { | ||
const response = await this.communicator.send<Methods.getOffChainSignature, string, string>( | ||
Methods.getOffChainSignature, | ||
messageHash, | ||
); | ||
return response.data; | ||
} | ||
async isMessageSigned(message: string | EIP712TypedData, signature = '0x'): Promise<boolean> { | ||
@@ -129,0 +138,0 @@ let check: (() => Promise<boolean>) | undefined; |
@@ -380,2 +380,13 @@ import SDK from '../sdk'; | ||
describe('SDK.safe.getOffChainSignature', () => { | ||
test('Should request the off-chain signature from the interface', () => { | ||
sdkInstance.safe.getOffChainSignature('0x123'); | ||
expect(postMessageSpy).toHaveBeenCalledWith( | ||
expect.objectContaining({ method: Methods.getOffChainSignature, params: '0x123' }), | ||
'*', | ||
); | ||
}); | ||
}); | ||
describe('SDK.safe.requestAddressBook', () => { | ||
@@ -382,0 +393,0 @@ const wrongPermissions = [ |
@@ -12,2 +12,3 @@ import { Methods } from '../communication/methods'; | ||
isObjectEIP712TypedData, | ||
SignMessageResponse, | ||
} from '../types'; | ||
@@ -36,3 +37,3 @@ | ||
async signMessage(message: string): Promise<SendTransactionsResponse> { | ||
async signMessage(message: string): Promise<SignMessageResponse> { | ||
const messagePayload = { | ||
@@ -42,3 +43,3 @@ message, | ||
const response = await this.communicator.send<Methods.signMessage, SignMessageParams, SendTransactionsResponse>( | ||
const response = await this.communicator.send<Methods.signMessage, SignMessageParams, SignMessageResponse>( | ||
Methods.signMessage, | ||
@@ -51,3 +52,3 @@ messagePayload, | ||
async signTypedMessage(typedData: EIP712TypedData): Promise<SendTransactionsResponse> { | ||
async signTypedMessage(typedData: EIP712TypedData): Promise<SignMessageResponse> { | ||
if (!isObjectEIP712TypedData(typedData)) { | ||
@@ -60,3 +61,3 @@ throw new Error('Invalid typed data'); | ||
SignTypedMessageParams, | ||
SendTransactionsResponse | ||
SignMessageResponse | ||
>(Methods.signTypedMessage, { typedData }); | ||
@@ -63,0 +64,0 @@ |
@@ -20,2 +20,3 @@ import { Methods } from '../communication/methods'; | ||
[Methods.getEnvironmentInfo]: EnvironmentInfo; | ||
[Methods.getOffChainSignature]: string; | ||
[Methods.requestAddressBook]: AddressBookItem[]; | ||
@@ -22,0 +23,0 @@ [Methods.wallet_getPermissions]: Permission[]; |
@@ -100,1 +100,5 @@ import { RPC_CALLS } from '../eth/constants'; | ||
} | ||
export interface SafeSettings { | ||
offChainSigning?: boolean; | ||
} |
@@ -65,2 +65,8 @@ import { ChainInfo as _ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'; | ||
export type OffChainSignMessageResponse = { | ||
messageHash: string; | ||
}; | ||
export type SignMessageResponse = SendTransactionsResponse | OffChainSignMessageResponse; | ||
export type SafeInfo = { | ||
@@ -67,0 +73,0 @@ safeAddress: string; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
151455
2861
606