-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from trustwallet/feat/erc20-permit-visualizati…
…on-support feat: add ERC20 permit for both legacy
- Loading branch information
Showing
5 changed files
with
187 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { ASSET_TYPE, Domain, PermitMessage, Result } from "../../types"; | ||
import { PROTOCOL_ID } from ".."; | ||
import { MaxUint256 } from "../../utils"; | ||
|
||
export const visualize = (message: PermitMessage, domain: Domain): Result => { | ||
if (!isERC20Permit(message)) throw new Error("wrong ERC20 Permit message schema"); | ||
const amount = | ||
message.value?.toString() || | ||
(message.allowed?.toString() === "true" ? MaxUint256.toString() : "0"); | ||
|
||
return { | ||
protocol: PROTOCOL_ID.ERC20_PERMIT, | ||
assetIn: [], | ||
assetOut: [], | ||
approval: [ | ||
{ | ||
address: domain.verifyingContract, | ||
type: ASSET_TYPE.ERC20, | ||
amounts: [amount], | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
owner: message.owner || message.holder!, // isERC20Permit makes sure one of theme exist at least | ||
operator: message.spender, | ||
deadline: Number(message.deadline || message.expiry) * 1000, | ||
}, | ||
], | ||
}; | ||
}; | ||
|
||
/** | ||
* @dev a function that return if a message is an ERC2612 or pseudo-ERC2612 (DAI example) | ||
* This function handles ERC2612 Permit and DAI Permit | ||
* @see https://eips.ethereum.org/EIPS/eip-2612 | ||
* @param message EIP-712 message | ||
* @returns Boolean | ||
*/ | ||
export const isERC20Permit = (message: object): boolean => { | ||
if (Object.keys(message).length !== 5) return false; | ||
const hasOwnProperty = Object.prototype.hasOwnProperty.bind(message); | ||
return ( | ||
(hasOwnProperty("owner") || hasOwnProperty("holder")) && | ||
hasOwnProperty("spender") && | ||
(hasOwnProperty("value") || hasOwnProperty("allowed")) && | ||
hasOwnProperty("nonce") && | ||
(hasOwnProperty("deadline") || hasOwnProperty("expiry")) | ||
); | ||
}; | ||
|
||
const erc20Permit = { | ||
visualize, | ||
isERC20Permit, | ||
}; | ||
|
||
export default erc20Permit; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { PermitMessage } from "../../../src/types"; | ||
import visualize from "../../../src/visualizer"; | ||
import erc20Permit from "../../../src/visualizer/erc20-permit"; | ||
|
||
describe("ERC20 Permit", () => { | ||
const erc20DaiPermitMessage = { | ||
holder: "0x36C1625E5Ee6FBFa9fadd4f75790275e5eaB7107", | ||
spender: "0x21C1625E5Ee6FBFa9fadd4f75790275e5eaB7009", | ||
allowed: true, | ||
nonce: "1", | ||
expiry: "167960665", | ||
}; | ||
|
||
const ERC2612Message = { | ||
owner: "0x36C1625E5Ee6FBFa9fadd4f75790275e5eaB7107", | ||
spender: "0x21C1625E5Ee6FBFa9fadd4f75790275e5eaB7009", | ||
value: "100000000000", | ||
nonce: "1", | ||
deadline: "167960665", | ||
}; | ||
const erc20PermitDomain = { | ||
name: "Dai Stablecoin", | ||
version: "1.1", | ||
chainId: "1", | ||
verifyingContract: "0x6B175474E89094C44Da98b954EedeAC495271d0F", | ||
}; | ||
|
||
it("should revert if erc20Permit module called with wrong message payload", () => { | ||
const deepCopiedMessage = JSON.parse(JSON.stringify(erc20DaiPermitMessage)); | ||
delete deepCopiedMessage["expiry"]; | ||
|
||
expect(() => { | ||
erc20Permit.visualize(deepCopiedMessage, erc20PermitDomain); | ||
}).toThrowError("wrong ERC20 Permit message schema"); | ||
}); | ||
|
||
it("should successfully visualize DAI approval", async () => { | ||
const result = await visualize<PermitMessage>( | ||
erc20DaiPermitMessage, | ||
erc20PermitDomain | ||
); | ||
|
||
expect(result).toEqual({ | ||
protocol: "ERC20_PERMIT", | ||
assetIn: [], | ||
assetOut: [], | ||
approval: [ | ||
{ | ||
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F", | ||
type: "ERC20", | ||
amounts: [ | ||
"115792089237316195423570985008687907853269984665640564039457584007913129639935", | ||
], | ||
owner: "0x36C1625E5Ee6FBFa9fadd4f75790275e5eaB7107", | ||
operator: "0x21C1625E5Ee6FBFa9fadd4f75790275e5eaB7009", | ||
deadline: 167960665000, | ||
}, | ||
], | ||
}); | ||
}); | ||
|
||
it("should successfully visualize DAI approval with zero amount", async () => { | ||
const result = await visualize<PermitMessage>( | ||
{ ...erc20DaiPermitMessage, allowed: false, nonce: "2" }, | ||
erc20PermitDomain | ||
); | ||
|
||
expect(result).toEqual({ | ||
protocol: "ERC20_PERMIT", | ||
assetIn: [], | ||
assetOut: [], | ||
approval: [ | ||
{ | ||
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F", | ||
type: "ERC20", | ||
amounts: ["0"], | ||
owner: "0x36C1625E5Ee6FBFa9fadd4f75790275e5eaB7107", | ||
operator: "0x21C1625E5Ee6FBFa9fadd4f75790275e5eaB7009", | ||
deadline: 167960665000, | ||
}, | ||
], | ||
}); | ||
}); | ||
|
||
it("should successfully visualize ERC2612 approval", async () => { | ||
const result = await visualize<PermitMessage>(ERC2612Message, erc20PermitDomain); | ||
|
||
expect(result).toEqual({ | ||
protocol: "ERC20_PERMIT", | ||
assetIn: [], | ||
assetOut: [], | ||
approval: [ | ||
{ | ||
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F", | ||
type: "ERC20", | ||
amounts: ["100000000000"], | ||
owner: "0x36C1625E5Ee6FBFa9fadd4f75790275e5eaB7107", | ||
operator: "0x21C1625E5Ee6FBFa9fadd4f75790275e5eaB7009", | ||
deadline: 167960665000, | ||
}, | ||
], | ||
}); | ||
}); | ||
}); |